Home > Net >  Why don't you need to pass the state to the reducer with react useReducer hook?
Why don't you need to pass the state to the reducer with react useReducer hook?

Time:09-03

If we look at the standard example of increment, decrement with useReducer hook:

const initialState = {count: 0};

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return {count: state.count   1};
    case 'decrement':
      return {count: state.count - 1};
    default:
      throw new Error();
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <>
      Count: {state.count}
      <button onClick={() => dispatch({type: 'decrement'})}>-</button>
      <button onClick={() => dispatch({type: 'increment'})}> </button>
    </>
  );
}

As I understand it, the useReducer function in the above code has bound 'dispatch' to the 'reducer' function so when we call dispatch it executes the reducer function. However, looking at the code the reducer function expects 2 params, however we only pass it one param when we execute dispatch - but it works. Why is this?.. many thanks.

CodePudding user response:

the arguments in reducer are handled by the useReducer hook automatically

the dispatch method in useReducer all it does is update the state with the appropriate action object in your case decrement or increment . So when dispatch call reducer the arguments in reducer are handled by the useReducer hook automatically : the state is known, and the action is just the argument of dispatch which is passed along to the reducer as its second argument.

CodePudding user response:

The dispatch() function is a child function returned by the useReducer(). This gives it scoped access to the reducer that you passed into the useReducer().

So when you call the dispatch() like so dispatch({type: 'decrement'}) the dispatch() will take the action that you passed to it and grab the reducer that you passed into the useReducer() and it will pass in the state and the action that you just passed into dispatch() to your reducer to get the desired state and use that value to set the state and re render the component.

So think of the useReducer() function something like the following:

const useReducer = (reducer, initialState) => {
  // react stuff being done here connect rendering and state
  // but for this example I will just hardcode the state to the initial state
  const state = initialState
  
  const dispatch = (action) => {
    // react will set the state with your reducer and re render the component
    React.dispatchState(reducer(state, action))
  }

  return [state, dispatch]
}

IMPORTANT: this is by no way the actual code react uses as the useReducer() but it will give you a good representation of how the code is working. You can see the source code here https://github.com/facebook/react/blob/main/packages/react/src/ReactHooks.js and follow the bread crumbs to see how react actually does it.

CodePudding user response:

The reducer function and the dispatch function are not the same. Here's an extremely simplified example that might help you think conceptually about the data flow.

Note that this is neither technically accurate nor really how the useReducer hook works. If you want to review the actual source code, here's the entrypoint for examination: the line where useReducer is exported from the codebase in the 18.2.0 release: https://github.com/facebook/react/blob/v18.2.0/packages/react/src/ReactHooks.js#L87

let state;

function useReducer (reducer, intialState) {
  state = intialState;

  const dispatch = (action) => {
    const next = reducer(state, action);
    const changed = !Object.is(state, next);
    state = next;
    if (changed) {
      // Causes React to re-render (code not shown)
    }
  };

  return [state, dispatch];
}

  • Related