当useEffect(React js)中的依赖项发生变化时,如何停止重新启动for循环



我正在尝试从输入中匹配pi值。"pracInput";useEffect中使用了依赖项,因此我可以从输入中获取最新值并进行检查。但问题是,当我输入一些值时,for循环会重新启动。

如果我输入9;期望值=14159;计数:5;进度宽度:60;

如果我输入另一个值2;预期=>值=141592;计数:6;进程宽度:72;

import React, { useEffect, useState } from "react";
const PiGame = () => {
const [pracInput, setPracInput] = useState("1415");
const pi = "141592653589793238462643";
const [widthText, setWidthText] = useState(0);
const [counting, setCounting] = useState(0);

useEffect(() => {
const runLoop2 = async () => {
for (let i = 0; i < pracInput.length; i++) {
await new Promise((resolve) => setTimeout(resolve, 1000));
if (pracInput[i] === pi[i]) {
console.log(i)
console.log(true);
setWidthText((prev) => prev + 12);
setCounting((prev) => prev + 1);
} else {
console.log(false);
alert('not match')
}
}
};
runLoop2();
}, [pracInput]);
const handleChange = (e) => {
const val = e.target.value;
if (/^[0-9]+$/.test(val)) {
setPracInput(val);
}
};

return (
<div>
<div>
value: <input
type="text"
style={{
width: "80%",
marginTop: 100,
height: 25,
fontSize:25
}}
value={pracInput}
onChange={handleChange}
/>

<div style={{ fontSize: 25 }}>counting : {counting}</div>
<div style={{ backgroundColor: "green", width: widthText, height: 20 }}></div>
<div>progress width : {widthText}</div>

</div>
</div>

);
};
export default PiGame;

根据我对问题的理解:

import React, { useEffect, useState } from "react";
const PiGame = () => {
const [pracInput, setPracInput] = useState("1415");
const pi = "141592653589793238462643";
useEffect(() => {
let subscribed = true;
const runLoop2 = async () => {
for (let i = 0; i < pracInput.length; i++) {
await new Promise((resolve) => setTimeout(resolve, 1000));
if (subscribed) {
if (pracInput[i] === pi[i]) {
console.log(i)
console.log(true);
} else {
console.log(false);
}
}
}
};
runLoop2();
return () => subscribed = false; // to avoid memory leak on unmount of component

}, []);. // Passing empty array will make it execute only once, at component mount
const handleChange = (e) => {
const val = e.target.value;
if (/^[0-9]+$/.test(val)) {
setPracInput(val);
}
};

return (
<div>
<div>
<input
type="text"
style={{
width: "80%",
}}
value={pracInput}
onChange={handleChange}
/>
<div>{pracInput}</div>
</div>
</div>

);
};
export default PiGame;

当您在useEffect中执行异步任务时,必须使用一些逻辑/技巧来避免内存泄漏。

因为您添加了"pracInput";在数组中"UseEffect";每次调用它时都会进行excutes,因此总是会调用循环函数来重新启动。要停止这种情况,您可以删除";pracInput";并以另一种方式获取值,或者您可以使用";UseState";hook在循环开始时设置一个特定的值,然后根据循环函数调用设置一个条件。像这样的

const [cond, setCond] = useState(false);

当循环开始时,将其值设置为true,然后添加类似的条件

if(cond == false)
runLoop2();

你在找这个吗?

import React, { useEffect, useState, useRef } from "react";
const PiGame = () => {
const [pracInput, setPracInput] = useState("1415");
const pi = "141592653589793238462643";
const counter = useRef(4); // store the counter
useEffect(() => {
const runLoop2 = async () => {
for (let i = counter.current; i < pracInput.length; i++) {
await new Promise((resolve) => setTimeout(resolve, 1000));
if (pracInput[i] === pi[i]) {
console.log(i)
console.log(true);
} else {
console.log(false);
}
}
counter.current = counter.current + pracInput.length;
};
runLoop2();
}, [pracInput]);
// the rest same as before

请参阅您的for循环存在于useEffect中,每当您的pracInput更改时,就会触发useEffect,因此useEffect内的所有内容都会被触发。当调用handleChange时,您的pracInput正在更改,这意味着当提供一些输入并且if (/^[0-9]+$/.test(val)) { setPracInput(val); }为true时,您将更改pracInput并触发useEffect,因此for循环将启动。由于for循环需要更改pracInput,所以将其移出useEffect也没有意义。如果你只想启动一次for循环,那么就把它从useEffect中删除,然后这样做:

useEffect(()=>{
for loop goes here
},[]);

这将确保for循环只运行一次,即组件将首次渲染时。

编辑:根据你的输出,我认为这应该有效:

const [widthText, setWidthText] = useState(0);
const [counting, setCounting] = useState(0);

useEffect(() => {
const TimeoutId = setTimeout(() => {
if(pracInput==="1415")
{
setCounting(4);
setWidthText(60);
}
else
{
setCounting(pracInput.length+1);
setWidthText(60+(pracInput.length-4)*12);
}
}, 1000);
return () => clearTimeout(TimeoutId);

}, [pracInput]);


const handleChange = (e) => {
const val = e.target.value;
if (/^[0-9]+$/.test(val)) {
setPracInput(val);
}
};

现在您可以删除for循环

最新更新