Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Issues with useReducer not synchronously updating the state

According to React docs :

useReducer is usually preferable to useState when you have complex state logic that involves multiple sub-values or when the next state depends on the previous one.

1. can somebody explain me why useReducer is not updating the state synchronously ?

const reducer = (state, action) => {
    if( action.type === 'ADD_VALUE') {
        console.log(`STATE IN REDUCER`, [...state, action.path]) // => ["1.1"]
        return [...state, action.path]
    }   
}

const [state, dispatch] = useReducer(reducer, [])

<input type="button" onClick={() => {
    dispatch({ type: 'ADD_VALUE', path: "1.1"})
    console.log(`STATE`, state) // => []
    // here i want to do some stuff based on the lastest updated state (["1.1"] and not [])
    // for example dispatch an action with redux
}}/>

2. How can I do some stuff (dispatch a redux action) based on the lastest updated state (["1.1"] and not []) ?

like image 448
Hayi Avatar asked Jan 29 '26 04:01

Hayi


1 Answers

Use useEffect to access the state correctly. You could add some safe-guarding if you want something invoking if a certain criterion is hit.

If you want to access your reducer across components, you can store the reducer using Context API. Look below for an example. You can see the reducer being injected into the Context on the parent component and then two child components that a) dispatches an action b) receives the update from the action.

1. Example of context reducer to use across multiple components

import React from "react";
import ReactDOM from "react-dom";

const Application = React.createContext({
  state: null,
  dispatch: null
});

function ActionComponent() {
  const { dispatch } = React.useContext(Application);
  return (
      <div>
          <div>Action Component</div>
          <button onClick={() => dispatch("lol")}>Do something</button>
      </div>
  );
}

function ListenerComponent() {
  const { state } = React.useContext(Application);
  React.useEffect(
    () => {
      console.log(state);
    },
    [state]
  );
  return <div>Listener Component</div>;
}

function App() {
  const [state, dispatch] = React.useReducer(function(state = [], action) {
    return [...state, action];
  });
  return (
    <Application.Provider value={{ state, dispatch }}>
      <div className="App">
        <ActionComponent />
        <ListenerComponent />
      </div>
    </Application.Provider>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

2. Example of local reducer without using Application Context

const reducer = (state, action) => {
    if( action.type === 'ADD_VALUE') {
        return [...state, action.path]
    }   
}

const [state, dispatch] = useReducer(reducer, [])

React.useEffect(() => {
    console.log(state);
}, [state]);

<input type="button" onClick={() => {
    dispatch({ type: 'ADD_VALUE', path: "1.1"})
}}/>
like image 51
Win Avatar answered Jan 30 '26 19:01

Win



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!