Implement redux and react-redux core code by yourself

I think the core logic of redux is the application of javascript closure + reasonable api. The core logic of react-redux is to link redux to the life cycle of react + reasonable api.

JavaScript closure example

const create = () => {
  let state;

  const getValue = () => state;

  const setValue = (value) => {
    state = value;
  };

  return { getValue, setValue };
};

Simply use the closure to store a state, we can implement the redux api:

const createStore = (reducer) => {
  let state;

  const getState = () => state;

  const dispatch = (action) => {
    state = reducer(state, action);
  };

  return { getState, dispatch };
};

Subscribe and unsubscribe

You can call subscribe to register a callback and call it at a specific moment.

const create = () => {
  let state;
  const listeners = [];

  const getValue = () => state;

  const setValue = (value) => {
    state = value;
    listeners.forEach((listener) => {
      listener();
    });
  };

  const subscribe = (callback) => {
    listeners.push(callback);
    return () => {
      listeners.splice(listeners.indexOf(callback), 1);
    };
  };

  return { getValue, setValue, subscribe };
};

Here are a few points

  1. The execution order of callback is the same as the registration order.
  2. Callback is executed synchronously. Compared with callback heavy, reducer heavy is obviously better.
  3. Unsubscribe is not declared, but callbacks that are actually useless will cause performance loss.

Redux will be optimized specifically, but the complexity will not change.

Link redux to react life cycle

react-redux is used to link redux to the life cycle of react

Above we have implemented the redux hook subscribe, and we have the react lifecycle hooks useState and useEffect. Now we can simply hook them up.





const useReduxState = (store) => {
  const [state, setState] = useState(store.getState);
  useEffect(
    () => {
      const unsubscribe = store.subscribe(setState);
      return unsubscribe;
    },
    [store],
  );
  return state;
};

Every time the store’s setValue method is called, it will trigger the callback and react’s setState hooks, thereby triggering the component render.

useSelector

The above useReduxState is difficult to formally use. Most of the time we only need a small part of the data in the store. In other words, we want to subscribe to the update of a part of the data instead of the update of the entire store, otherwise we will get too many updates.

useSelector is solving this problem.

const useSelector = (store, selector) => {
  const [state, setState] = useState(store.getState);
  useEffect(
    () => {
      const unsubscribe = store.subscribe(() => {
        const state = store.getState();
        const selectState = selector(state);
        if (!isStrictEqual(state, selectState)) {
          setState(selectState);
        }
      });
      return unsubscribe;
    },
    [store, selector],
  );
  return state;
};

Here, by selecting first, then comparing strictEqual, a part of pruning is performed. If the selected data does not change, rendering will not occur. If the select process is heavy, you can further use reselect to optimize.

Leave a Reply

Your email address will not be published. Required fields are marked *