yongchang
yongchang

Reputation: 522

React array did not update despite using useEffect

I am trying to add an element into an array after I click the "click me" button. I did a console log to make sure it went inside the function, but despite the function being call, nothing changes.

I also try using useEffect to check if my variable got update

Relevant code:

import React, { useState, useEffect } from "react";

export default function App() {
  let [test, setTest] = useState(["1", "2", "3"]);

  const onChange = () => {
    console.log("onChange");
    test.unshift("4");
  };

  const cards = () => {
    return (
      <div>
        {test.map((item, i) => (
          <ul key={i}>
            <li>{item}</li>
          </ul>
        ))}
      </div>
    );
  };

  useEffect(() => {
    console.log("cardData ", test);
  }, [test]);

  return (
    <div className="App">
      <button onClick={() => onChange()}>Click me</button>
      {cards()}
    </div>
  );
}

Really need some advice on where did i go wrong

This is my codesandbox link

Upvotes: 2

Views: 1441

Answers (5)

Amila Senadheera
Amila Senadheera

Reputation: 13265

The issue is that you directly mutate the test (test.unshift does mutate the test instance) and rendering does not happen since no reference change was detected (shallow reference is used when rendering happens).

Try this

  const onChange = () => {
    console.log("onChange");

    const testCopy = [...test];
    testCopy.unshift("4");
    setTest(testCopy);
  };

Code sandbox => https://codesandbox.io/s/dark-wildflower-lkf4u?file=/src/App.js:160-302

Another NOT working case can be given like below due to using the same instance reference (test).

  const onChange = () => {
    console.log("onChange");
    test.unshift("4");
    setTest(test);
  };

Upvotes: 2

Gabriele Petrioli
Gabriele Petrioli

Reputation: 196306

There are 2 issues with your code

  1. you are mutating the state with test.unshift
  2. you do not use the setTest

try

  const onChange = () => {
    console.log("onChange");
    const updatedTest = [...test];
    updatedTest.unshift("4");
    setTest(updatedTest);
  };

Upvotes: 0

Sojin Antony
Sojin Antony

Reputation: 2237

It is because you are directly mutating the state, you need to use the useState function hook to update the value of a state variable.

here is my solution https://codesandbox.io/s/determined-perlman-436el?file=/src/App.js:0-727

export default function App() {
  let [test, setTest] = useState(["1", "2", "3"]);

  const onChange = () => {
    console.log("onChange");
    setTest(["4", ...test]);
  };

  const cards = () => {
    return (
      <div>
        {test.map((item, i) => (
          <ul key={i}>
            <li>{item}</li>
          </ul>
        ))}
      </div>
    );
  };

  useEffect(() => {
    console.log("cardData ", test);
  }, [test]);

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      <button onClick={() => onChange()}>Click me</button>
      {cards()}
    </div>
  );
}

Upvotes: 0

NeERAJ TK
NeERAJ TK

Reputation: 2695

You are altering the state test directly without using setTest .

Mutating the state directly breaks the primary principle of React's unidirectional data flow, making your app fragile and basically ignoring the whole component lifecycle.

Upgrade your onChange function as:

  const onChange = () => {
    console.log("onChange");
    setTest([...test, "4"]);
  };

Check demo.

Upvotes: 0

Aarni Joensuu
Aarni Joensuu

Reputation: 751

You are not calling the setTest function, which is the only thing you should be using to mutate the array test. Set the new value using setTest and you should be fine.

Upvotes: 0

Related Questions