Home > Mobile >  React state reset when re-render occurs
React state reset when re-render occurs

Time:10-14

I wanted to make several input elements and print summation of them. So I wrote JSX code like this.

const Input = ({reportUpdate}) => {
    const [previous, updatePrevious] = React.useState(0);

    const onUpdate = (e) => {
        reportUpdate(e.target.value - previous);
        updatePrevious(e.target.value);
    }

    return (
        <input type='number' onChange={onUpdate}/>
    )
}

const Series = () => {
    const [total, updateTotal] = React.useState(0);
    const [inputs, updateInputs] = React.useState([]);

    const updateReported = (delta) => {
        console.log('delta: ' delta ', total: ' total);
        updateTotal(( total)   ( delta));
    }
    console.log('total: ' total);

    const addInput = () => {
        updateInputs(inputs.concat([<Input reportUpdate={updateReported}/>]));
    }

    return (
        <div>
            {inputs}
            <p>total: {total}</p>
            <button onClick={addInput}>Add input</button>
        </div>
    )
}

const root = ReactDOM.createRoot(document.getElementById('react'));
root.render(<Series/>);

My compile environment: 7.18.10 (@babel/core 7.19.0) (NPM Babel)

The problem is that state total repeatedly reset to it's initial state(0). Here's my test step.

  1. Add 3 input by clicking Add input button three times.
  2. Write '12' to first input field after this, console log printed
total: 0
delta: 1, total: 0
total: 1
delta: 11, total: 0
total: 11

In my intention, state total must be set to 1 in 4th line of log, but it doesn't.

I changed initial state of total and repeated test.

const [total, updateTotal] = React.useState(10);

and console log printed

total: 10
delta: 1, total: 10
total: 11
delta: 11, total: 10
total: 21

it seems pretty sure that total is not set by updateTotal but useState().

what tricky is, making Input by hardcoding, not array, thing goes ok. Below code worked as intended.

const Input = ({reportUpdate}) => {
    const [previous, updatePrevious] = React.useState(0);

    const onUpdate = (e) => {
        reportUpdate(e.target.value - previous);
        updatePrevious(e.target.value);
    }

    return (
        <input type='number' onChange={onUpdate}/>
    )
}

const Series = () => {
    const [total, updateTotal] = React.useState(10);

    const updateReported = (delta) => {
        console.log('delta: ' delta ', total: ' total);
        updateTotal(( total)   ( delta));
    }
    console.log('total: ' total);

    return (
        <div>
            <Input reportUpdate={updateReported}/>
            <Input reportUpdate={updateReported}/>
            <Input reportUpdate={updateReported}/>
            <p>total: {total}</p>
        </div>
    )
}

const root = ReactDOM.createRoot(document.getElementById('react'));
root.render(<Series/>);

So, I think that problem is adding Input element by array, but I cannot figure out why exactly this happens and how to solve this. Can anyone help?!

CodePudding user response:

Try with this

const updateReported = (delta) => {
    console.log('delta: ' delta ', total: ' total);
    updateTotal((prev) => prev   ( delta));
}

Refer below from react official docs for more info https://reactjs.org/docs/hooks-reference.html#functional-updates

CodePudding user response:

I come across this a lot, you can try:

const updateReported = (delta) => {
    console.log("delta: "   delta   ", total: "   total);
    updateTotal((prev) => prev   delta);
  };

It works for me - this way your total variable is always up to date :)

The reason this happens is because of the closure. When you first create a new input, its updateReported function will think the value of the total variable will be whatever it was when it was first created.

CodePudding user response:

Your issue is that you're putting your components in a React state with the updateReported version when your total is 0.

Instead of storing your components in the state. Try storing an ID to use as key and render them on map.

Like this...

https://codesandbox.io/s/loving-sea-oihz5n?file=/public/index.html:0-1544

  • Related