Разбираемся со связкой React и Redux на простейшем примере
14.06.2018
/
oberset
Простой пример, который поможет быстро разобраться, как управлять данными с помощью библиотеки Redux в ваших приложениях на React.
Настройка проекта
Первое, что нам необходимо сделать перед запуском приложения на React – это настроить сборщик Webpack и трансформатор javascript-кода Babel. Вначале установим нужные npm-пакеты:
Скачиваем Webpack:
npm install -g webpack webpack-cli
Скачиваем Babel и необходимые плагины:
npm install --save-dev babel-core babel-loader babel-polyfill babel-preset-es2015 babel-preset-react babel-plugin-transform-decorators-legacy babel-plugin-transform-class-properties
Скачиваем React и Redux:
npm install --save react react-dom prop-types redux react-redux
После установки npm-пакетов, в корневой папке проекта нужно создать конфигурационные файлы webpack.config.js и .babelrc.
Содержимое файла webpack.config.js:
'use strict';
var path = require("path");
module.exports = {
mode: 'development',
entry: {
"index": "./index.js"
},
output: {
path: path.join(__dirname, "build"),
filename: "[name].bundle.js"
},
module: {
rules: [
{
test: /\.js$/,
use: "babel-loader"
}
]
},
devtool: "source-map",
watch: true,
watchOptions: {
aggregateTimeout: 300
}
};
Содержимое файла .babelrc:
{
"presets": ["react", "es2015"],
"plugins": [
"transform-decorators-legacy",
"transform-class-properties"
]
}
Теперь создадим в корневой папке проекта файлы index.js и index.html.
Файл index.js:
console.log('Start React Application!!!')
Файл index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Test react-redux</title>
</head>
<body>
<div ></div>
<script src="build/index.bundle.js"></script>
</body>
</html>
Запускаем webpack из корневой папки:
webpack-cli
После запуска webpack должен создать js-файл index.bundle.js и положить его в папку build (как мы указали в конфиге). Если все прошло успешно, то в консоли отобразится примерно такое содержимое:
Попробуем открыть файл index.html в браузере:
После настройки проекта можно переходить непосредственно к разработке нашего приложения с использованием React и Redux.
Взаимодействие React и Redux на примере отображения значения счетчика
Для демонстрации примера работы библиотеки Redux в связке с React, создадим небольшое приложение, которое будет отображать в браузере значение счетчика. Так как кода в нашем проекте будет совсем немного, для наглядности примера мы не будем разбивать приложение на множество файлов (хотя в реальном проекте это будет обязательно), а объединим весь код в файле index.js.
Откроем файл index.js, созданный нами ранее и вместо вывода сообщения в консоль, подключим следующие пакеты:
import React from 'react';
import ReactDOM from 'react-dom';
import {createStore, combineReducers} from 'redux';
import {Provider, connect} from 'react-redux';
import PropTypes from 'prop-types';
Тут мы импортировали сам фреймворк «реакт», пакет react-dom для отображения реакт-компонентов в структуре DOM браузера, функции библиотеки Redux и пакет «react-redux», который и осуществляет взаимодействие «реакта» и «редукса».
Добавим код для установки значения счетчика:
let counter = 1;
const counterReducer = (state = null, action) => {
switch (action.type) {
case 'TEST':
return action.counter;
default:
return state;
}
};
const store = createStore(
combineReducers({counter: counterReducer}),
{counter}
);
Redux хранит все данные приложения в едином хранилище (store), который создается с помощью функции createStore. В нашем примере store хранит только одно поле counter. Для обновления значения в store нужно создать функцию, которая принимает в качестве параметров текущее значение state и действие action. Действие – это обычный javascript-объект, состоящий из типа действия (обязательного поля type) и произвольных полей, из которых потом можно вернуть новое значение для store. В нашем случае функция counterReducer возвращает новое значение счетчика из поля action.counter. В функции также производится проверка action.type, чтобы обрабатывать только указанный тип действий.
В качестве второго параметра в функцию createStore можно передать исходное состояние хранилища, мы таким образом можем установить начальное значение счетчика из переменной counter.
Подпишемся на обновление хранилища, чтобы выводить в консоль текущее состояние:
store.subscribe(() => console.log(store.getState()));
Далее создадим React-компонент для отображения счетчика:
@connect(
state => ({
counter: state.counter
}),
dispatch => ({})
)
class App extends React.Component {
static contextTypes = {
store: PropTypes.object
};
render() {
return (
<h1>Counter value: {this.props.counter}</h1>
);
}
}
Декоратор @connect, добавленный к компоненту, производит привязку значения из хранилища store к свойству компонента. Т.е значение поля counter из store теперь можно прочитать из this.props.
Далее нам остается отобразить компонент в браузере используя метод render из пакета «react-dom» и добавить тестовую функцию для обновления значения счетчика:
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('test-app')
);
setInterval(() => {
store.dispatch({
type: 'TEST',
counter: ++counter
});
}, 1000);
Компонент Provider из пакета «react-redux» добавляет store ко всем вложенным компонентам. Метод store.dispatch запускает механизм обновления хранилища, в качестве параметра он принимает объект действия, состоящий из типа действия и нового значения счетчика.
После запуска примера в браузере, можно увидеть, как значение счетчика каждую секунду увеличивается на 1. Каждое обновление состояния хранилища выводится в консоль.
Полный код приложения:
import React from 'react';
import ReactDOM from 'react-dom';
import {createStore, combineReducers} from 'redux';
import {Provider, connect} from 'react-redux';
import PropTypes from 'prop-types';
let counter = 1;
const counterReducer = (state = null, action) => {
switch (action.type) {
case 'TEST':
return action.counter;
default:
return state;
}
};
const store = createStore(
combineReducers({counter: counterReducer}),
{counter}
);
store.subscribe(() => console.log(store.getState()));
@connect(
state => ({
counter: state.counter
}),
dispatch => ({})
)
class App extends React.Component {
static contextTypes = {
store: PropTypes.object
};
render() {
return (
<h1>Counter value: {this.props.counter}</h1>
);
}
}
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('test-app')
);
setInterval(() => {
store.dispatch({
type: 'TEST',
counter: ++counter
});
}, 1000);
Надеюсь, этот простейший пример поможет вам разобраться с использованием связки React и Redux.
Иногда внутри React-компонента требуется повесить DOM-событие на window или document, например, если нужно добавить обработчик события resize или scroll окна браузера.
Компонент высшего порядка в React (Higher Order Component или сокращенно HOC) – это простая javascript-функция, которая принимает на вход один или несколько компонентов и возвращает другой компонент.
Прежде всего давайте разберемся, что такое внутреннее состояние компонента в React и для чего оно может понадобиться. После этого поговорим об особенностях работы метода setState.