React
Некоторые небольшие проекты, просто используйтеReact
Вполне достаточно, использование управления даннымиprops
,state
Вот и все, когда вам нужно импортироватьRedux
Шерстяная ткань?
При рендеринге данные компонента передаются черезprops
При выборке из родительского компонента это обычно имеет местоA --> B
, но с ростом сложности бизнеса может быть так:A --> B --> C --> D --> E
,E
Необходимые данные должны быть получены изA
пройти тудаprops
пройти, и соответствующийE --> A
Передать обратный вызов в обратном направлении. Компоненту BCD эти данные не нужны, но его нужно пропускать через них, что действительно немного неудобно, а прохождениеprops
так же какcallback
Повторное использование компонентов BCD также окажет влияние. Или какие-то данные нужно разделить между родственными компонентами, а передавать, получать и т.д. не очень удобно. В таких случаях необходимо внедрять Redux.
фактически
A --> B --> C --> D --> E
В этом случае React может получать данные без использования props послойной передачи, использоватьContextВот и все. быть упомянутым позжеreact-redux
черезContext
Пусть каждый подкомпонент получаетstore
данные в .
Redux
На самом деле, мы просто хотим найти место для хранения каких-то общих данных, каждый может их получить, и каждый может их модифицировать, вот и все.
Можно ли поместить его в целую переменную? Да, конечно, но это слишком неэлегантно и небезопасно, потому что это глобальная переменная, любой может получить к ней доступ и изменить ее, и она может быть случайно перезаписана мелким партнером. Если глобальных переменных недостаточно, используйте приватные переменные.私有变量
,不能轻易被修改
, вы сразу подумали о闭包
сейчас...
Теперь нам нужно написать функцию, которая удовлетворяет:
- хранить объект данных
- Внешний мир может получить доступ к этим данным
- Внешний мир также может изменять эти данные.
- Уведомлять подписчиков об изменении данных
function createStore(reducer, initialState) {
// currentState就是那个数据
let currentState = initialState;
let listener = () => {};
function getState() {
return currentState;
}
function dispatch(action) {
currentState = reducer(currentState, action); // 更新数据
listener(); // 执行订阅函数
return action;
}
function subscribe(newListener) {
listener = newListener;
// 取消订阅函数
return function unsubscribe() {
listener = () => {};
};
}
return {
getState,
dispatch,
subscribe
};
}
const store = createStore(reducer);
store.getState(); // 获取数据
store.dispatch({type: 'ADD_TODO'}); // 更新数据
store.subscribe(() => {/* update UI */}); // 注册订阅函数
Шаги, которые необходимо выполнить для обновления данных:
- Что: что вы хотите сделать --- диспетчеризация (действие)
- Как: как это сделать, результат --- reducer(oldState, action) => newState
- Затем?: повторно выполнить функцию подписки (например, повторно отобразить пользовательский интерфейс и т. д.)
Таким образом реализуется хранилище, предоставляющее центр хранения данных для внешнего доступа, модификации и т.д. В этом основная идея Redux. Следовательно, Redux не имеет существенного отношения к React, и Redux можно обычно использовать в сочетании с другими библиотеками. Просто метод управления данными Redux очень совместим с концепцией представления, управляемого данными React, что делает разработку очень удобной.
Теперь, когда у нас есть безопасное место для доступа к данным, как мы можем интегрировать его в React?
Мы можем создатьwindow.store = createStore(reducer)
Затем пройдите, где это необходимоstore.getState()
чтобы получить данные поstore.dispatch
обновить данные поstore.subscribe
чтобы подписаться на изменения данных, а затем продолжитьsetState
...было бы ошеломляюще сделать это во многих местах, и все же не избежатьНеизящность глобальных переменных.
React-Redux
Так как глобальные переменные имеют много недостатков, то измените способ мышления и интегрируйте хранилище непосредственно в пропсы верхнего уровня приложения React, при условии, что каждый подкомпонент может получить доступ к пропсам верхнего уровня, например:
<TopWrapComponent store={store}>
<App />
</TopWrapComponent>,
React просто предоставляет такой хук,Context, использование очень простое, просто посмотрите официальную демоверсию, чтобы понять. Теперь, когда каждый подкомпонент может легко получить доступ к хранилищу, следующим шагом для подкомпонента является извлечение, изменение и подписка на обновление пользовательского интерфейса данных, используемых в хранилище. Каждый дочерний компонент должен сделать это один раз, очевидно, должен быть более удобный способ:компоненты более высокого порядка. через компоненты более высокого порядкаstore.getState()
,store.dispatch
,store.subscribe
При инкапсуляции подкомпонент не знает о хранилище.Подкомпонент обычно использует свойства для получения данных и обычно использует обратный вызов для запуска обратного вызова, что эквивалентно отсутствию хранилища.
Вот грубая реализация этого компонента более высокого порядка:
function connect(mapStateToProps, mapDispatchToProps) {
return function(WrappedComponent) {
class Connect extends React.Component {
componentDidMount() {
// 组件加载完成后订阅store变化,如果store有变化则更新UI
this.unsubscribe = this.context.store.subscribe(this.handleStoreChange.bind(this));
}
componentWillUnmount() {
// 组件销毁后,取消订阅事件
this.unsubscribe();
}
handleStoreChange() {
// 更新UI
this.forceUpdate();
}
render() {
return (
<WrappedComponent
{...this.props}
{...mapStateToProps(this.context.store.getState())} // 参数是store里面的数据
{...mapDispatchToProps(this.context.store.dispatch)} // 参数是store.dispatch
/>
);
}
}
Connect.contextTypes = {
store: PropTypes.object
};
return Connect;
};
}
При использовании подключения мы знаем, что нужно написать некоторый шаблонный код, напримерmapStateToProps
,mapDispatchToProps
Эти две функции:
const mapStateToProps = state => {
return {
count: state.count
};
};
const mapDispatchToProps = dispatch => {
return {
dispatch
};
};
export default connect(mapStateToProps, mapDispatchToProps)(Child);
// 上述代码执行之后,可以看到connect函数里面的
<WrappedComponent
{...this.props}
{...mapStateToProps(this.context.store.getState())}
{...mapDispatchToProps(this.context.store.dispatch)}
/>
// 就变成了
<WrappedComponent
{...this.props}
{count: store.getState().count}
{dispatch: store.dispatch}
/>
// 这样,子组件Child的props里面就多了count和dispatch两个属性
// count可以用来渲染UI,dispatch可以用来触发回调
Итак, это нормально? OK. Хранилище центра обработки данных генерируется через замыкание, а затем хранилище привязывается к пропсам верхнего уровня React.Подкомпоненты устанавливают соединение с пропсами верхнего уровня через HOC, а затем получают данные, модифицируют данные и обновляют Пользовательский интерфейс. Здесь мы в основном говорим о том, как все три объединяются.Если вы хотите узнать о более продвинутых функциях, таких как промежуточное программное обеспечение redux, разбиение редуктора и другие параметры подключения, вы можете взглянуть на соответствующий исходный код.