如何在 setTimeout 中使用钩子?



我有一个简单的程序来生成数组。我添加了在单击按钮时反转数组的功能,但是当我单击反向时,显示的数组不是反转而是保持原样。我正在使用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;

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;
}
}

工作示例:

演示

编辑

插入timeout以进行可视化1s每次迭代中都有时差。

这是我可以给你的建议:

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的重现。

请注意,当您更改数组的大小时,反向行为很奇怪,我不知道它来自我的代码还是您的代码,我会尝试弄清楚。

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


[编辑]:好的,错误来自反向索引未重置的事实。我编辑了代码以添加"shouldReverseArray"状态。我在jsx的"onClick"事件中调用它。很脏,但我不能在这里想别的东西。希望它对:)有所帮助

相关内容

  • 没有找到相关文章

最新更新