Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

New React Context API + LocalStorage + Subscribe (Replacement for Redux)

I have an app using Redux. Is stores the global state as shown below:

Create Store:

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;

Handles Local Storage

  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;
  }
};

Finaly starts the app session:

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'));

It works perfectly. So my question is: Is there any possibility to do the same with the new React Context API?

I am pretty confortable using the new context, I just want to know about store, localstorage, subscribe. So the the state is persisted even when the user leaves the app.

like image 334
Fernando Lopes Avatar asked Aug 03 '18 12:08

Fernando Lopes


People also ask

Can react context API replace Redux?

Sometimes Redux is overkill for simple applications, even with Redux Toolkit. Context, on the other hand, is not a replacement for Redux.

Can I use localStorage instead of Redux?

It's probably OK to use localstorage instead of Redux. It's possible to have changes in localstorage have immediate effect on subscribed react components. The people at marmelab who built react-admin transitioned from using redux to what they call The Store.

How do I store API data in localStorage in react JS?

Saving data to localStorage in React is super easy: const [data, setData] = useState([]); useEffect(() => { localStorage. setItem('dataKey', JSON. stringify(data)); }, [data]);


2 Answers

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
  };
};

Then for individual pages you can have actions and initial store value like this

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);

Finally in your pages/HomePage/index.js you can have import { Provider } from './store';

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

and in your pages/HomePage/Homepage.js you can have

render() {
      return (
        <Consumer>
          {({ state, actions }) => {
            return this.renderChildrens(state, actions);
          }}
        </Consumer>
      );
    }
  }
like image 125
VivekN Avatar answered Oct 28 '22 13:10

VivekN


First things first

  • Redux has nothing to do with react in specific, it is a state manager.
    it helps you manage a big JavaScript object that holds the state of your application.

  • react's Context API is not even a new feature in react, it was there the whole time and it just got a new face. It's a way to pass down data to children without prop drilling.

I think you are referring to react-redux.
react-redux is an abstraction, a way to bind your Redux store to react. It's doing all the store subscription for you and help you create a Container and consumers using the connect HOC and the Provider component.
It also helps with passing down the store object (via the context API under the hood).

If you are using Redux already, i don't see any point for not using react-redux.

You can read in more details about the differences In this post (full disclosure, I'm the author).

like image 41
Sagiv b.g Avatar answered Oct 28 '22 12:10

Sagiv b.g