19

I'm trying to figure out the working of React Hook API. I'm trying to add a number to a list. The code that I commented, i.e myArray.push... doesn't seem to perform the operation, though the code below it is working fine. Why is it so?

import React, {useState} from 'react'

export default () => {

  const [myArray, setArray] = useState([1,2,3])

  return (
    <div>
      {myArray.map((item=>{

        return <li>{item}</li>

      }))}
      <button onClick = {()=>{

        // myArray.push(myArray[myArray.length-1]+1)
        // setArray(myArray)

        setArray([...myArray, myArray[myArray.length-1]+1])

      }}>Add</button>
    </div>
  )
}
6
  • Is there any reason you're trying to implement a stateful component as a functional component? Commented Feb 19, 2019 at 15:55
  • 17
    @SZenC why wouldn't they, now that hooks exist? Commented Feb 19, 2019 at 15:56
  • 2
    I believe myArray is this.state.myArray and as usual, you shouldn't mutate the state so previously you never this.state.myArray.push(....), which also means you shouldn't try to myArray.push now Commented Feb 19, 2019 at 15:58
  • 3
    [...myArray, myArray[myArray.length-1]+1] !== myArray, which will cause the component to re-render. Commented Feb 19, 2019 at 16:01
  • 1
    @JithinKs That's right. React will do a strict === comparison under the hood, and since myArray.push just adds another element to the existing array, it will not re-render. [...myArray, myArray[myArray.length-1]+1] however creates an entirely new array. If you stick to the rule of thumb to not mutate the state directly, you will not run into these issues. Commented Feb 19, 2019 at 16:18

4 Answers 4

24

I would recommend using useReducer for anything more complicated than a single value.

function App() {
  const [input, setInput] = useState(0);

  const [myArray, dispatch] = useReducer((myArray, { type, value }) => {
    switch (type) {
      case "add":
        return [...myArray, value];
      case "remove":
        return myArray.filter((_, index) => index !== value);
      default:
        return myArray;
    }
  }, [1, 2, 3]);

  return (
    <div>
      <input value={input} onInput={e => setInput(e.target.value)} />
      <button onClick={() => dispatch({ type: "add", value: input})}>
        Add
      </button>

      {myArray.map((item, index) => (
        <div>
          <h2>
            {item}
            <button onClick={() => dispatch({ type: "remove", value: index })}>
              Remove
            </button>
          </h2>
        </div>
      ))}
    </div>
  );
}
Sign up to request clarification or add additional context in comments.

Comments

8

You aren't mutating the array in the commenting code and hence when you try to setState, hooks internally check that the same state is being passed due to reference not updating for myArray and hence, won't trigger a re-render again.

However in the working code, you are creating a new array instance and hence the update is working correctly

1 Comment

So you have to clone an array to update an array...? That seems necessarily expensive no?
2

You can use a way to deep clone an object and use it as a temporary variable to change the value of your array.

Here an example with your code :

import React, { useState } from 'react'

export default () => {
  const [myArray, setArray] = useState([1, 2, 3])
  var tmpArray = JSON.parse(JSON.stringify(myArray))

  return (
    <div>
      {myArray.map((item) => {
        return <li>{item}</li>
      })}
      <button
        onClick={() => {
          tmpArray.push(tmpArray[tmpArray.length - 1] + 1)
          setArray(tmpArray)
        }}
      >
        Add
      </button>
    </div>
  )
}

Comments

0

Using map works better.

    setArray(array.map(f=>{
        if(f.name===name) f.checked = checked //your code here
        return f
    }))

Comments

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.