17

I'm trying to update a UI using React Hooks and a form. I have a state set to monitor the value on the form and when I click submit, I want to add this value to an array (held in state) and display it on the UI. My problem is that when I submit the value, although it is added to the array (and state is updated), the UI only updates when I change the value in the input.

My Component is as follows:

const PushToArrayUpdateState = () => {

    const [array, setArray] = useState([]);
    const [formVal, setFormVal] = useState(``);

    const handleSubmit = event => {
        event.preventDefault();
        let updateArray = array;
        updateArray.push(formVal);
        console.log(updateArray);
        setArray(updateArray);
    };

    return (
        <div>
            <form onSubmit={handleSubmit}>
                <input type="text" name="arrayVal" onChange={e => setFormVal(e.target.value)} />
                <input type="submit" value="Submit" />
            </form>
            <div>
                {array.map((val, index) => <p key={index}>{val}</p>)}
            </div>
        </div>
    );
};

You can also see this [not] working at: https://codesandbox.io/s/p3n327zn3q

Has anyone got any suggestions as to why the setArray in the handleSubmit function is not automatically causing the component to re-render?

2 Answers 2

47

Instead of

let updateArray = array;

Try this:

const updateArray = [...array];

https://codesandbox.io/embed/qxk4k3zmzq

Because arrays in JS are reference values, so when you try to copy it using the = it will only copy the reference to the original array.

Sign up to request clarification or add additional context in comments.

3 Comments

Dumb question but I can't figure out the right term to google, whats the "..." doing in [...array]. You answer was super helpful btw, thanks!
@cwmacken "Spread Operator" is what you're looking for. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
what if this array is an "Array of Objects", and only the object or value of object changes. And array size and array remains the same ?
5

A similar bug can happen with the same manifestation:

const [bought, setBought] = useState([])

...


bought.push(newItem)
setBought(bought)

To fix this you need to use

const newBought = [...bought, newItem] <- new reference
setBought(newBought) 

1 Comment

This is exactly the cause. Excellent explanation! Thanks a lot Tim!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.