Всем привет! Камол здесь. Эта статья — мой взгляд на библиотеку, которую я использую каждый день: Redux. Последние несколько лет я работаю в экосистеме ReactJS. Я недавно (в прошлом году) взял Redux. До Redux я пробовал несколько реализаций потока, но они не совсем то, что я хочу от слоя данных. Либо потому, что он не делает то, что мне нужно, либо требует слишком много изменений в текущей кодовой базе. Redux — это отдельная история. Он отлично работает на нескольких крупных проектах в моей нынешней компании. В Redux много крутых идей: однонаправленный поток данных, один источник правды и неизменяемость среди прочего. Они значительно упрощают мой рабочий процесс. Теперь так легко отлаживать код. И у него есть универсальная система промежуточного программного обеспечения. Выбор Redux был правильным шагом.
Тем не менее, Redux не является универсальным решением. Это государственная библиотека управления. Очень самоуверенный, я бы сказал. При разработке магазина Redux следует помнить о нескольких вещах:
- Redux не является частью React
- Несколько магазинов против одного магазина с несколькими редьюсерами
- Действия являются чистыми функциями и должны возвращать объект
- Отправить
- Использование реакции-редукции
Редукс! == Реагировать
Я думаю, само собой разумеется, что React и Redux — это две разные вещи. Redux не зависит от библиотеки React, и наоборот. React позаботится о логике представления, а Redux позаботится о логике данных. Redux можно интегрировать в любое внешнее приложение с помощью React, Angular или Backbone. Вы даже можете использовать Redux в чистом проекте JavaScript без фреймворка.
Редукторы
То, что большинству людей нужно осознать, когда они впервые начинают использовать Redux, — это концепция редюсера. Redux хранит ВСЕ данные о состоянии в одном большом объекте. Некоторые могут называть его «деревом состояний». Но в большинстве случаев вы не меняете все в дереве. Вот почему вам нужно «свести» его к подмножеству дерева, с которым вы хотите работать. Это способ структурировать состояние в приложении.
На практике редуктор — это функция с двумя аргументами, которая всегда возвращает объект:
const defaultState = {}; function myReducer(state = defaultState, action) { switch(action.type) { default: return state; } }
Эта функция используется в первый раз для инициализации этой части дерева состояний. В настоящее время этот редьюсер ничего не делает, кроме передачи текущего состояния. Теперь предположим, что у нас есть значение типа string.
const CHANGE_MY_VALUE = 'CHANGE_MY_VALUE'; const defaultState = { myValue: '' }; function myReducer(state = defaultState, action) { switch(action.type) { case CHANGE_MY_VALUE: return { myValue: action.newValue }; default: return state; } }
Теперь наш редьюсер готов принять новое действие типа CHANGE_MY_VALUE.
Действия
Существует только один единственный экземпляр, который содержит все данные о состоянии. И вы меняете любую часть информации, отправляя действие в магазин. Действие — это функция, которая возвращает объект. Возвращаемый объект всегда должен содержать тип. Redux использует «тип», чтобы выяснить, что делать с состоянием.
function changeMyValue(newValue) { return { type: CHANGE_MY_VALUE, newValue: newValue }; }
Дело в том, что если вы попытаетесь выполнить эту функцию сейчас, она ничего не сделает с магазином Redux. Потому что для того, чтобы уведомить Redux о нашем «намерении», нам нужно использовать один из API Redux. Вам нужна еще одна функция под названием Dispatch.
Отправлять
Давайте сложим все кусочки вместе. Во-первых, нам нужен магазин
import { createStore } from 'redux'; import { myReducer } from './myReducer'; const TheStore = createStore(myReducer);
TheStore — это новый экземпляр магазина Redux. Он имеет одно поле «myValue». Он также имеет две функции, которые вы можете использовать:
- getState() — возвращает все текущее состояние магазина
- dispatch() — способ связи с магазином
Чтобы изменить данные внутри хранилища, вы «отправляете» действие, вызывая
import { changeMyValue } from './changeMyValue'; console.log(TheStore.getState().myValue); // empty string TheStore.dispatch(changeMyValue('alkazar!')); console.log(TheStore.getState().myValue); // alkazar!
Использование реакции-редукции
Мы прошли базовую механику магазина Redux. Теперь вы можете с удовольствием использовать Redux с ванильным JavaScript. Однако использование Redux с существующим фреймворком довольно многословно. Итак, хорошие люди в сообществе Redux пишут «адаптеры» для вас. В большинстве популярных фреймворков этот адаптер уже есть. Просто выполните поиск через регистратор npm. Теперь, поскольку я большой поклонник React и работаю с ним недавно, пример с React кажется логичным выбором ;)
import React from 'react'; const MyReactView = React.createClass({ propTypes: { myValue: React.PropTypes.string.isRequired }, onClick() { this.props.changeMyValue('!razakla'); }, render() { return (<div> <span>myValue:{this.props.myValue}</span> <button onClick={this.onClick}>Change</button> </div>); } });
Теперь, чтобы подключить Redux
import { connect } from 'react-redux'; import MyReactView from './MyReactView.jsx'; import { changeMyValue } from './changeMyValue'; function mapStateToProps(getState) { const { myValue } = getState(); return { myValue }; } function mapDispatchToProps(dispatch) { return { changeMyValue: function(newValue) { dispatch(changeMyValue(newValue)); } }; } export default connect(mapStateToProps, mapDispatchToProps)(MyReactView);
Connect() — это функция более высокого порядка. Функция высшего порядка — это функция, которая возвращает новую функцию. Думайте об этом как о способе реализации фабричного шаблона. Connect() принимает два аргумента: mapStateToProps и MapDispatchToProps.
- MapStateToProps — это способ чтения данных из хранилища Redux. Он предоставляет одну функцию getState() для получения текущего состояния из хранилища. все, что возвращается из этой функции, будет объединено с реквизитами компонента React, с которым вы вызываете connect(). В этом примере вы получите this.props.myValue
- MapDispatchToProps — это способ сопоставить действие хранилища с реквизитами компонента React, с которым вы вызываете connect(). В этом примере вы получите this.props.changeMyValue()
Резюме
Этого простого примера должно быть более чем достаточно, чтобы начать работу с Redux. В мире Redux есть еще кое-что. Вы можете добавить промежуточное ПО, чтобы выполнить действие более высокого порядка с помощью redux-thunk. Вы можете выходить из дерева состояний для консоли каждый раз, когда отправляется действие, и многое другое в соответствии с вашими потребностями.
В настоящее время в большом, большом мире JavaScript существует слишком много библиотек. Пройти их все невозможно. Но уверяю вас, приобретение Redux было одним из самых стоящих решений, которые я принял в этом году. Помимо кристально чистого API, Redux имеет очень активное сообщество разработчиков, поддерживающее его. Многие живые проекты сегодня с большим успехом используют Redux. Вы просто не ошибетесь с Redux.
Если вам нужна помощь в интеграции Redux или React в ваш проект, я буду рад пообщаться. Напишите мне электронную почту, и я свяжусь с вами.