反应-在setTimeout中使用钩子

时间:2020-06-20 17:17:33

标签: reactjs react-hooks settimeout visualization

我有一个生成数组的简单程序。我添加了单击按钮时反转阵列的功能,但是当我单击反转时,显示的阵列不是反转而是保持原样。我正在使用setTimeout,因此可以看到它。为什么不进行可视化?

这是我的代码:

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

const Dummy2 = () => {
    const [arr, setArr] = useState([]);
    const [length, setLength] = useState(10);

    useEffect(() => {
        generateArray();
    }, [length]);

    const generateArray = () => {
        const temp = [];
        for(let i = 0; i < length; i++) {
            temp.push(i + 1);
        }
        setArr(temp);
    }

    const handleLength = (e) => {
        setLength(e.target.value);
    }

    const reverseArray = () => {
        let delay = 1;
        for(let i = 0; i < length / 2; i++) {
            setTimeout(() => {
                const temp = arr;
                const t1 = arr[i];
                const t2 = arr[length - 1 - i];
                temp[i] = t2;
                temp[length - 1 - i] = t1;
                setArr(temp);
            }, delay * 1);
            delay++;
        }
    }

    const printArray = () => {
        console.log(arr);
    }

    const maxVal = Math.max(...arr);
    
    return (
        <div>
            <div className="array-container" style={{height: '50%'}}>
                {arr.map((value, idx) => (
                    <div className="array-element"
                         key={idx}
                         style={{height: `${(value * 100 / maxVal).toFixed()}%`,
                                 width: `calc(${100 / length}% - 2px)`,
                                 margin: '0 1px',
                                 display: 'inline-block',
                                 backgroundColor: 'black',
                                 color: 'white'}}
                    >{value}</div>))
                }
            </div>
            <div>
                <button onClick={() => generateArray()}>New array</button>
                <button onClick={() => reverseArray()}>Reverse</button>
                <button onClick={() => printArray()}>Print array</button>
            </div>
            <div className="slider-container">
                1
                <input type="range" 
                       min="1" 
                       max="100" 
                       onChange={(e) => handleLength(e)} 
                       className="slider" 
                       id="myRange" 
                />
                100
            </div>
            {length}
        </div>
    );
}

export default Dummy2;

2 个答案:

答案 0 :(得分:1)

reverseArray函数中,您每次迭代都设置状态,从而在那引起错误。

您需要完全反转数组,然后将其分配给状态。

更改您的reverseArray功能,如下所示:

  const reverseArray = () => {
    const temp = [...arr];
    let delay = 1000;
    for (let i = 0; i < length / 2; i++) {
      setTimeout(() => {
        const t1 = arr[i];
        const t2 = arr[length - 1 - i];
        temp[i] = t2;
        temp[length - 1 - i] = t1;
        setArr([...temp]);
      }, delay);
      delay+=1000;
    }
  }

工作示例:

Demo

编辑

插入timeout以便在每次迭代中显示1s时差。

答案 1 :(得分:0)

以下是我可以向您建议的内容:

import React, { Component } from "react";
import { render } from "react-dom";
import React, { useState, useEffect } from "react";

const Dummy2 = () => {
  const [arr, setArr] = useState([]);
  const [length, setLength] = useState(10);
  const [reverseIndex, setReverseIndex] = useState(0);
  const [didMount, setDidMount] = useState(true);
  const [shouldReverseArray, setShouldReverseArray] = useState(true);

  useEffect(() => {
    generateArray();
  }, [length]);

  useEffect(() => {
    // After clicking on 'reverse' button, reverseIndex is edited. Thus this effect is triggered because it listen to 'reverseIndex'. DidMount is here to prevent triggering the effect when the component is mounted
    if (!didMount) {
      if (shouldReverseArray && reverseIndex < length / 2) {
        setTimeout(() => reverseArray(), 1000);
      } else {
        shouldReverseArray = setShouldReverseArray(false);
        setReverseIndex(0);
      }
    } else {
      setDidMount(false);
    }

  }, [reverseIndex]);

  const generateArray = () => {
    const temp = [];
    for (let i = 0; i < length; i++) {
      temp.push(i + 1);
    }
    setArr(temp);
  };

  const handleLength = e => {
    setLength(e.target.value);
  };

  const reverseArray = () => {
    const temp = Object.assign([], arr); // Make a copy of your state because it is not mutable
    const tempStart = temp[reverseIndex];
    const tempEnd = temp[length - tempStart];
    temp[reverseIndex] = tempEnd;
    temp[length - tempStart] = tempStart;
    setArr(temp); // Set the new arr
    setReverseIndex(prevState => ++prevState); // Set the new index
  };

  const printArray = () => {
    console.log(arr);
  };

  const maxVal = Math.max(...arr);

  return (
    <div>
      <div className="array-container" style={{ height: "50%" }}>
        {arr.map((value, idx) => (
          <div
            className="array-element"
            key={idx}
            style={{
              height: `${((value * 100) / maxVal).toFixed()}%`,
              width: `calc(${100 / length}% - 2px)`,
              margin: "0 1px",
              display: "inline-block",
              backgroundColor: "black",
              color: "white"
            }}
          >
            {value}
          </div>
        ))}
      </div>
      <div>
        <button onClick={() => generateArray()}>New array</button>
        <button onClick={() => {setShouldReverseArray(true); reverseArray()}}>Reverse</button>
        <button onClick={() => printArray()}>Print array</button>
      </div>
      <div className="slider-container">
        1
        <input
          type="range"
          min="1"
          max="100"
          onChange={e => handleLength(e)}
          className="slider"
          id="myRange"
        />
        100
      </div>
      {length}
    </div>
  );
};

export default Dummy2;

render(<Dummy2 />, document.getElementById("root"));

这里是Stackblitz repro

请注意,当您更改数组的大小时,请怪异地反向操作,我不知道它是来自我的代码还是您的代码,我会尽力弄清楚。

此外,如果您不需要显示每个更改,则可以使用.reverse(),这样会更容易。


[编辑]:好的,该错误来自于reverseIndex未被重置的事实。我编辑了代码以添加“ shouldReverseArray”状态。我在jsx的“ onClick”事件中称呼它。很脏,但是我在这里不能考虑其他事情。希望对您有帮助:)