Новый React Context API + LocalStorage + Subscribe (замена Redux)

У меня есть приложение, использующее 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'));

Работает отлично. Итак, мой вопрос: есть ли возможность сделать то же самое с новым API контекста React?

Мне довольно удобно использовать новый контекст, я просто хочу знать о магазине, локальном хранилище, подписке. Таким образом, состояние сохраняется, даже когда пользователь покидает приложение.


person Fernando Lopes    schedule 03.08.2018    source источник


Ответы (2)


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 вы можете импортировать {Provider} из './store';

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

и на ваших страницах / HomePage / Homepage.js вы можете иметь

render() {
      return (
        <Consumer>
          {({ state, actions }) => {
            return this.renderChildrens(state, actions);
          }}
        </Consumer>
      );
    }
  }
person VivekN    schedule 07.08.2018

В первую очередь о главном

  • Redux не имеет ничего общего с react в частности, это менеджер состояний.
    он помогает вам управлять большим объектом JavaScript, который хранит состояние вашего приложения.

  • Контекстный API-интерфейс react - это даже не новая функция в React, она была там все время и только что приобрела новое лицо. Это способ передать данные детям без бурения опор.

Я думаю, вы имеете в виду react-redux.
react-redux - это абстракция, способ заставить ваш магазин Redux реагировать. Он выполняет всю подписку магазина за вас и помогает вам создавать Container и потребителей, используя connect HOC и компонент Provider.
Он также помогает передавать объект магазина (через контекстный API под капотом).

Если вы уже используете Redux, я не вижу смысла не использовать react-redux.

Подробнее о различиях вы можете прочитать В этом посте (полное раскрытие, я автор).

person Sagiv b.g    schedule 07.08.2018