Home > Blockchain >  How can I update State properly in switch case in a loop
How can I update State properly in switch case in a loop

Time:10-09

I want to update state like [1, 2, 3] but what I'm wrong here and how to fix it.

codesanbox: https://codesandbox.io/s/infallible-mendeleev-6641iw?file=/src/App.js:0-642

import "./styles.css";
import { useEffect, useState } from "react";

export default function App() {
  const [value, setValue] = useState([]);

  useEffect(() => {
    run();
  }, []);

  const run = () => {
    for (let i = 0; i < 10; i  ) {
      let copy = i;
      switch (copy) {
        case 1:
          setValue([...value, copy]);
          break;
        case 2:
          setValue([...value, copy]);
          break;
        case 3:
          setValue([...value, copy]);
      }
    }
  };

  return (
    <div className="App">
      {value.map((item, index) => {
        return <h2>{value[index]}</h2>;
      })}
    </div>
  );
}

CodePudding user response:

The problem is that every time you do setValue([...value, copy]), you're overwriting the previous time you did it. value is unchanging in that loop.

Instead, build the new array and then set it in state. And any time you're building new state based on existing state, it's generally best to use the callback form of the state setter (to ensure that you're not starting with a stale version of value).

Example:

const run = () => {
    setValue((oldValue) => {
        const newValue = [...oldValue];
        for (let i = 0; i < 10; i  ) {
            let copy = i; // ** There's no need for this, just use `i`
            switch (copy) {
                case 1:
                    newValue.push(copy); // It's not clear to me why...
                    break;
                case 2:
                    newValue.push(copy); // ...every case does the same..
                    break;
                case 3:
                    newValue.push(copy); // ...thing, but I replicated it
                    break;
            }
        }
        return newValue;
    });
};

Old version showing the problem:

const { useEffect, useState } = React;

/*export default*/ function App() {
    const [value, setValue] = useState([]);

    useEffect(() => {
        run();
    }, []);

    const run = () => {
        for (let i = 0; i < 10; i  ) {
            let copy = i;
            switch (copy) {
                case 1:
                    setValue([...value, copy]);
                    break;
                case 2:
                    setValue([...value, copy]);
                    break;
                case 3:
                    setValue([...value, copy]);
            }
        }
    };

    return (
        <div className="App">
            {value.map((item, index) => {
                return <h2>{value[index]}</h2>;
            })}
        </div>
    );
}
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);
<div id="root"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>

New version showing the solution:

const { useEffect, useState } = React;

/*export default*/ function App() {
    const [value, setValue] = useState([]);

    useEffect(() => {
        run();
    }, []);

    const run = () => {
        setValue((oldValue) => {
            const newValue = [...oldValue];
            for (let i = 0; i < 10; i  ) {
                let copy = i; // ** There's no need for this, just use `i`
                switch (copy) {
                    case 1:
                        newValue.push(copy); // It's not clear to me why...
                        break;
                    case 2:
                        newValue.push(copy); // ...every case does the same..
                        break;
                    case 3:
                        newValue.push(copy); // ...thing, but I replicated it
                        break;
                }
            }
            return newValue;
        });
    };

    return (
        <div className="App">
            {value.map((item, index) => {
                return <h2>{value[index]}</h2>;
            })}
        </div>
    );
}
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);
<div id="root"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>


Side note: You need key props on those h2 elements in the map callback.

CodePudding user response:

Oh, I know how to make state become [1, 2, 3]

just use the previous value in every setState();

    for (let i = 0; i < 10; i  ) {
      let copy = i;
      switch (copy) {
        case 1:
          setValue((value) => [...value, copy]);
          break;
        case 2:
          setValue((value) => [...value, copy]);
          break;
        case 3:
          setValue((value) => [...value, copy]);
      }
    }
  };
  • Related