1

I was learning React Hooks and was trying to get how useState works with arrays. So, I have this code:

    const App = () => {
      const initialTodos = [
  {
    id: 'a',
    task: 'Learn React',
    complete: true,
  },
  {
    id: 'b',
    task: 'Learn Firebase',
    complete: true,
  },
  {
    id: 'c',
    task: 'Learn GraphQL',
    complete: false,
  },
];
      const [todos, setTodos] = useState(initialTodos);
      const [task, setTask] = useState('');
      const handleChangeInput = event => {
        setTask(event.target.value);
      };
      const handleSubmit = event => {
        if (task) {
          setTodos(todos.concat({ id: 'd', task, complete: false }));
        }
        setTask('');
        event.preventDefault();
      };
      ...
    };

The question I wanted to ask is that why do we use concat to immutably add new object into array what if mutate and use push()?

Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
SAM
  • 941
  • 1
  • 9
  • 16
  • 1
    *The `concat()` method is used to merge two or more arrays. This method does not change the existing arrays, but instead returns a new array.* - [.concat()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat) – norbitrial Apr 20 '20 at 15:43
  • @norbitrial, hi)), sorry but we need to change the existing array, why do we need to return a new array? – SAM Apr 20 '20 at 15:47
  • You can also use spread syntax instead of concat `setTodos([ ...todos, { id: 'd', task, complete: false }]);` – Mahdi N Apr 20 '20 at 15:50
  • `why do we need to return a new array?` because react assumes state is immutable. https://reactjs.org/tutorial/tutorial.html#why-immutability-is-important . If you mutate the array, react can not tell that it changed. – Nicholas Tower Apr 20 '20 at 15:51
  • 1
    Does this answer your question? [Why can't I directly modify a component's state, really?](https://stackoverflow.com/questions/37755997/why-cant-i-directly-modify-a-components-state-really) – Emile Bergeron Apr 20 '20 at 16:11

2 Answers2

2

what if mutate and use push()?

As said in react docs:

Never mutate this.state directly, as calling setState() afterwards may replace the mutation you made. Treat this.state as if it were immutable.

Reasons:

1/ setState works in batches, which means one cannot expect the setState to do the state update immediately, it is an asynchronous operation so the state changes may happen in later point in time which means manually mutating state may get overriden by setState.

2/ Performance. When using pure component or shouldComponentUpdate, they will do a shallow compare using === operator, but if you mutate the state the object reference will still be the same so the comparison would fail.

Source: this excellent medium article.

Mahdi N
  • 2,128
  • 3
  • 17
  • 38
0
setTodos(prevTodos => prevTodos.concat({ id: 'd', task, complete: false }));

Don't forget that todos is an array.

Kid
  • 1,160
  • 2
  • 14
  • 31
  • @O.o, sorry but why do we need to return new array? what if we change the existing array with push()? – SAM Apr 20 '20 at 15:52
  • 2
    it won't trigger re-render. you are not allowed to mutate the state directly – Kid Apr 20 '20 at 15:53
  • 1
    `[...todos]` is not needed since concat doesn't mutate. You can either do `[...todos, newTodo]` or `todos.concat(newTodo)` – HMR Apr 20 '20 at 16:28