如何使用 React 和 useEffect 更改数组中的位置?

How to change places in an Array using React and useEffect?

有一个包含 5 个元素的列表。默认情况下,列表(数组)应显示 ["A"、"B"、"C"、"D"、"E"]。元素应该每秒旋转一个位置:

1 秒后列表:["B", "C", "D", "E", "A"];

2 秒后:["C"、"D"、"E"、"A"、"B"];

3 秒后:[“D”、“E”、“A”、“B”、“C”];

我正在学习,我需要帮助。你会如何解决这个问题?这是我的错误解决方案:

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

function App() {
  const [term, setTerm] = useState();
  const [letter, setLetter] = useState([]);

  let array = ["A", "B", "C", "D", "E"];

  useEffect(() => {
    const interval = () =>
      setInterval(() => {
        array.push(array.shift());
        setLetter(array);
       }, 1000);

    interval();

    return clearInterval(interval);
  }, [array]);

  return (
    <div className="center">
      <input
        type="text"
        value={term}
        onChange={(e) => setTerm(e.target.value)}
      />
      {letter &&
        letter.map((l, i) => {
          return (
            <ul key={l}>
              <li>{l[0]}</li>
              <li>{l[1]}</li>
              <li>{l[1]}</li>
              <li>{l[3]}</li>
              <li>{l[4]}</li>
            </ul>
          );
        })}
    </div>
  );
}

export default App;

我只是一个学习者,我被困住了,我需要帮助。它变化很快,就像每 50 毫秒。

我会分析答案并从中学习,因为我自己做不到。

这里发生的是你有一个 useEffect 附加到 array 的变化,它在间隔回调中多次变化。

  1. 更改:array.shift() -> 触发 useEffect
  2. 更改:array.push() -> 同时触发 useEffect

这复合并开始快速改变数组。

我建议使用数组副本或类似的东西。

setInterval(() =>
  let copy = […array];
  copy.push(copy.shift());
  setLetter(copy);
  array = copy
}, 1000);

只是另一个建议。我也会尽量不使用额外的 array 变量,因为该数据已经存储在 letter 中。 以下是我将如何做这件事。

const [letter, setLetter] = useState(["A", "B", "C", "D", "E"]);

useEffect(() => {
  setTimeout(() =>
    let copy = […letter];
    copy.push(copy.shift());
    setLetter(copy);
  }, 1000);
}, [letter]);

我没有测试这个,所以我希望它能有所帮助。

我建议您避免修改数组。不是使用 pushshift,而是通过 arr => [...arr .slice (1), arr [0]] 或使用 concat:

生成数组的新版本

const {useState, useEffect} = React;

const App = () => {
  const [letters, setLetters] = useState (["A", "B", "C", "D", "E"])

  useEffect(() => {
    const timer = setTimeout (
      () => setLetters (arr => arr .slice (1) .concat (arr [0])), 
      1000
    )
    return () => clearTimeout (timer)
 })

  return (<div>{letters .join (' ')}</div>)
}

ReactDOM .render (<App/>, document .getElementById ("main"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="main"></div>

仅通过 setter 修改数据使事情更加一致。

请注意,即使不返回 clearTimeout 也能正常工作,但这可能是一个好习惯。