0

I am using react and Immer to make a very simple frontend. The data I need to display is simple nested Json. The json is stored at the top of the tree in a state, and a simple reducer using immer allow editing of the json. I want to add a button that trigger a refresh of the json state from the json on the server.

function SectionRender(props){
    
      const [jsonData, jsonDispatch] = useImmerReducer(jsonDataReducer, props.json);
      const handleRefreshClick = () => jsonDispatch({ type:"refresh"})
return  <div> 
        /* rest of display */ 
        <button onClick={handleRefreshClick}>Reinitialiser</button>
        </div>
}

This is the top. and it goes with the reducer:

function jsonDataReducer(draft, action) {
    switch (action.type) {
        /* other cases for edit */
        case "refresh":
            const newStuff = getServerData().then(
            (value) => {
                console.log("we got something");
                //something that would modify the state here??
            },
            () => {
                console.log("no server response")           
            })
            break;
        default:
            break;
    }
}

I tried returning the "new stuff" value. But since its a promise, the whole state become a promise and the rest of display crash when it tries to render. Modification of the draft in the .then() dont seem to work either (presumably because the function already long returned the mutable draft).

It seems obvious I might not have structured things properly, but I cannot figure how I'm supposed to structure it, or what I'm supposed to do to allow the state to be modified from asynchronous function call.

lethargie
  • 15
  • 3

1 Answers1

2

Reducers are pure functions and you should avoid to add any side effects like async calls in it. So try to exclude this async logic outside the reducer (during handleRefreshClick) and once you receives the output back from the async call then dispatch action with the data received back from call to modify the state.

like

const handleRefreshClick = () => {
    getServerData().then(
        (value) => {
            jsonDispatch({ type:"refresh", data: value})
        },
        () => {
            console.log("no server response")           
        })
}
  • I realized as I took out async call from the reducer, that this create another closely related problem. How can I push the state back to the server if not in the reducer? – lethargie Dec 23 '21 at 21:31