Связь между реакцией, редукцией, реакцией-редукцией

внешний интерфейс React.js обратный Redux

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, разбиение редуктора и другие параметры подключения, вы можете взглянуть на соответствующий исходный код.