新的 React Context API + LocalStorage + Subscribe(替代 Redux)

Posted

技术标签:

【中文标题】新的 React Context API + LocalStorage + Subscribe(替代 Redux)【英文标题】:New React Context API + LocalStorage + Subscribe (Replacement for Redux) 【发布时间】:2019-01-11 08:01:49 【问题描述】:

我有一个使用 Redux 的应用程序。 Is 存储全局状态,如下图:

创建商店:

import createStore, applyMiddleware from 'redux';
import rootReducer from '../reducers';
import thunk from 'redux-thunk';

const configureStore = initialState => 
  return createStore(
    rootReducer,
    initialState,
    applyMiddleware(thunk)
  );
;

export default configureStore;

处理本地存储

  const storageName = 'xxxState';
  export const loadState = () => 
  try 
    const serializedState = localStorage.getItem(storageName);
    if (serializedState === null) 
      return undefined;
    
    return JSON.parse(serializedState);
   catch(err) 
    return undefined;
  
;

export const saveState = state => 
  try 
    const serializedState = JSON.stringify(state);
    localStorage.setItem(storageName, serializedState);
   catch(err) 
    throw err;
  
;

最后启动应用会话:

import React from 'react';
import ReactDOM from 'react-dom';
import Start from './start';
import  Provider  from 'react-redux';
import configureStore from './store/configureStore';
import  loadState, saveState  from './store/localStorage';
import throttle from 'lodash/throttle';

const persistedState = loadState();

const store = configureStore(persistedState);
store.subscribe(throttle(() => 
  saveState(store.getState());
, 1000));

ReactDOM.render(
  <Provider store=store>
    <Start />
  </Provider>,
  document.getElementById('root'));

完美运行。所以我的问题是:有没有可能对新的 React Context API 做同样的事情?

使用新的上下文我很舒服,我只想了解 store、localstorage 和 subscribe。因此,即使用户离开应用程序,状态也会保持不变。

【问题讨论】:

【参考方案1】:

store.js

import React,  Component, createContext  from "react";

export const createStore = store => 
  const Context = createContext();
  let self;
  const setState = (action, state, args) => 
    self.setState(state);
  ;
  const actions = Object.keys(store.actions).reduce(
    (accumulator, currentValue) => 
      return 
        ...accumulator,
        [currentValue]: function(...args) 
          let result = store.actions[currentValue](
             state: self.state, actions: self.value.actions ,
            ...args
          );
          if (result) 
            result.then
              ? result.then(result => setState(currentValue, result, args))
              : setState(currentValue, result, args);
          
        
      ;
    ,
    
  );
  class Provider extends Component 
    constructor() 
      super();
      this.state = store.initialState;
      self = this;
      this.value = 
        actions,
        state: this.state
      ;
    
    render() 
      if (this.state !== this.value.state) 
        this.value = 
          actions,
          state: this.state
        ;
      
      return (
        <Context.Provider value=this.value>
          this.props.children
        </Context.Provider>
      );
    
  
  class Consumer extends Component 
    renderProps = ( actions, state ) => 
      // const  mapStateToProps, mapDispatchToProps  = this.props;
      return this.props.children(
        state: state,
        actions: actions
      );
    ;
    render() 
      return <Context.Consumer>this.renderProps</Context.Consumer>;
    
  
  const connect = (mapStateToProps, mapDispatchToProps) => WrappedComponent => 
    return (
      <Consumer
        mapStateToProps=mapStateToProps
        mapDispatchToProps=mapDispatchToProps
      >
        injectedProps => (
          <WrappedComponent ...injectedProps ...this.props />
        )
      </Consumer>
    );
  ;
  return 
    Provider,
    Consumer,
    connect
  ;
;

然后对于单个页面,您可以像这样进行操作和初始存储值

import  createStore  from "@src/store";
import  Actions  from "../actions";
import  storage  from "@helpers/storage";
import constants from "@src/constants";

import  util  from "@src/utils";

function getInitialState() 
  let Id = null;
  if (storage.get(constants.STORAGE_KEY)) 
    let storageObject = storage.get(constants.STORAGE_KEY);
    Id = storageObject["Id"];
    selectedDate = storageObject["selectedDate"];
  
  return 
    data: null,
    activeTab: "score",
    Id: Id
  ;

const store = 
  initialState: getInitialState(),
  actions: Actions
;

export const  Provider, Consumer  = createStore(store);

终于在你的页面/HomePage/index.js 你可以有 从 './store' 导入 Provider ;

render() 
  return (
    <Provider>
     <Homepage user=user children=children />
    </Provider>
  );

在你的页面/HomePage/Homepage.js 你可以有

render() 
      return (
        <Consumer>
          ( state, actions ) => 
            return this.renderChildrens(state, actions);
          
        </Consumer>
      );
    
  

【讨论】:

【参考方案2】:

首要任务

Redux 具体与react 无关,它是一个状态管理器。 它可以帮助您管理一个包含应用程序状态的大型 javascript 对象。

react 的 Context API 甚至不是 React 中的一个新特性,它一直都在那里,只是换了一张新面孔。这是一种将数据传递给没有prop drilling 的孩子的方法。

我认为您指的是react-reduxreact-redux 是一种抽象,一种绑定您的 Redux 存储以做出反应的方法。 它正在为您完成所有商店订阅,并帮助您创建 Container 和使用 connect HOC 和 Provider 组件的消费者。 它还有助于传递存储对象(通过底层的上下文 API)。

如果您已经在使用Redux,我认为不使用react-redux 没有任何意义。

您可以阅读更多关于差异的详细信息In this post(完全公开,我是作者)。

【讨论】:

以上是关于新的 React Context API + LocalStorage + Subscribe(替代 Redux)的主要内容,如果未能解决你的问题,请参考以下文章

新的 React Context API 会触发重新渲染吗?

新的 React Context API + LocalStorage + Subscribe(替代 Redux)

在组件之间路由时如何保持 React 新的 Context API 状态?

React API

React Context API 很慢

使用Context API示例解释的React高阶组件