pepinillo6969
pepinillo6969

Reputation: 463

How can split nested setStates when the children needs the parent previous state?

I have a warning on this nested setState pointing a "bad setState call" because I am calling a setState inside a setState, so I understand I must avoid that and take out the children setState from there, the problem is that the children is using the parent prevState for a conditional so I don't know how to solve this.

This is my code:

const setStateImageAndIndex = (state, image) => {
        setSketchState(prevState => {
            if (state.index !== undefined && prevState.index !== state.index) {
                setCurrentSketchIndex(state.index);
            }

            const new_state = {
                ...prevState,
                ...state,
                image: image
            };

            return new_state;
        });
    };

The warning is pointing the setCurrentSketchIndex(state.index); explicitly, which is the function I want to take out from setSketchState. Thank you!

Upvotes: 0

Views: 26

Answers (3)

pepinillo6969
pepinillo6969

Reputation: 463

According to the comments above from @GabrielePetrioli and @GiovanniEsposito, this solution seemed to be safer.

const setStateImageAndIndex = (state, image) => {

    let updateCurrentSketchIndex = false;

    setSketchState(prevState => {
        if (state.index !== undefined && prevState.index !== state.index) {
            updateCurrentSketchIndex = true;
        }

        const new_state = {
            ...prevState,
            ...state,
            image: image
        };

        return new_state;
    });

    if (updateCurrentSketchIndex) {
        setCurrentSketchIndex(state.index);
    }
};

Upvotes: 0

oieduardorabelo
oieduardorabelo

Reputation: 2985

you can hold the previous state of the parent component in a useRef and derivate the state in the child component passing that value down as a prop, for example:

function Parent() {
  let [state, setState] = React.useState({ version: 1 });
  let prevState = usePrevious(state.version);
  return (
    <div>
      <p>Parent value: {state.version}</p>
      <Child value={prevState} />
      <button
        onClick={() =>
          setState({
            version: state.version + 1
          })
        }
      >
        Update version
      </button>
    </div>
  );
}

function Child(props) {
  return (
    <div>
      <p>Child value: {props.value || "No value yet"}</p>
    </div>
  );
}

as we can see above, the parent component will update the state.version in the button click and usePrevious will hold the previous value:

function usePrevious(value) {
  const ref = React.useRef();
  React.useEffect(() => {
    ref.current = value;
  });
  return ref.current;
}

Working example in: https://codesandbox.io/s/use-previous-hook-0iemv

enter image description here

Upvotes: 0

Giovanni Esposito
Giovanni Esposito

Reputation: 11166

prevState in setSketchState infact is the actual state of sketchState (I mean the state setted by setSketchState). So you could write something like:

const setStateImageAndIndex = (state, image) => {
        if (state.index !== undefined && sketchState.index !== state.index) {
           setCurrentSketchIndex(state.index);
        }
        setSketchState(prevState => {
            const new_state = {
                ...prevState,
                ...state,
                image: image
            };

            return new_state;
        });
    };

Upvotes: 2

Related Questions