React UseState 在 eventListener 中被调用了两次
React UseState is called twice inside eventListener
我开始在空闲时间学习 React。启动 Hooks 时,会调用两次 setState 方法。
实时代码在
https://codesandbox.io/s/elastic-saha-mdwwc?file=/src/App.js
当我按 enter 键时,添加按钮起作用 fine.But,setState 函数被调用两次。最初的想法是内容重新 rendered.But 我将 useEffect 依赖项作为一个空数组。所以没有重新渲染,我不知道如何调试它。感谢您的帮助:)
const App = () => {
const [text, setText] = useState('');
const [list, setList] = useState([]);
const addToList = () => {
if (text !== '') {
setList([...list, text]);
setText('');
}
}
const deleteItem = index => {
const deletedList = list.filter((_, i) => i !== index);
setList(deletedList)
}
useEffect(() => {
console.log("Reloaded");
const listener = e => {
if (e.code === 'Enter') {
console.log("event triggered")
setText(text => {
if (text !== '') {
console.log("updating")
setList(a => ([...a, text]));
}
return ''
});
}
}
document.getElementById('textbox').addEventListener('keyup', listener);
console.log('Event registered')
return () => {
document.getElementById('textbox').removeEventListener('keyup', listener);
console.log('Event deregistered')
}
}, [])
return (
<div >
<input type="text" id="textbox" onChange={(e) => setText(e.target.value)} value={text} />
<button id="add" onClick={addToList}> Add</button>
<ul>
{
list.map((a, i) => <li key={i}>{a} <button type="button" onClick={() => deleteItem(i)}>Delete</button></li>)
}
</ul>
</div>
);
}
export default App;
我认为这是因为您代码中的 useEffect
:
setText(text => {
if (text !== '') {
console.log("updating")
setList(a => ([...a, text]));
}
return ''
});
将其更改为以下内容:
useEffect(() => {
console.log("Reloaded");
const listener = (e) => {
if (e.code === "Enter") {
console.log("event triggered");
if (text !== "") {
console.log("updating");
setList((a) => [...a, text]);
}
return "";
}
};
document.getElementById("textbox").addEventListener("keydown", listener);
console.log("Event registered");
return () => {
document
.getElementById("textbox")
.removeEventListener("keydown", listener);
console.log("Event deregistered");
};
}, [text]);
或者,
useEffect(() => {
console.log("Reloaded");
const listener = (e) => {
if (e.code === "Enter") {
console.log("event triggered");
if (e.target.value !== "") {
console.log("updating");
setList((a) => [...a, e.target.value]);
}
e.target.value = "";
return "";
}
};
document.getElementById("textbox").addEventListener("keydown", listener);
console.log("Event registered");
return () => {
document
.getElementById("textbox")
.removeEventListener("keydown", listener);
console.log("Event deregistered");
};
});
或者,
这个使用了onKeyPress
事件并且在挂载组件时只运行useEffect
一次
import React, { useState, useEffect } from "react";
const App = () => {
const [text, setText] = useState("");
const [list, setList] = useState([]);
const addToList = () => {
if (text !== "") {
setList([...list, text]);
setText("");
}
};
const deleteItem = (index) => {
const deletedList = list.filter((_, i) => i !== index);
setList(deletedList);
};
const listener = (e) => {
e.stopPropagation();
if (e.key === "Enter") {
console.log("event triggered");
if (text !== "") {
console.log("updating");
setList((a) => [...a, text]);
}
setText("");
return "";
}
};
// not needed, only here to show it only runs once
useEffect(() => {
console.log("Reloaded");
}, []);
return (
<div>
<input
type="text"
id="textbox"
onChange={(e) => setText(e.target.value)}
onKeyPress={listener}
value={text}
/>
<button id="add" onClick={addToList}>
{" "}
Add
</button>
<ul>
{list.map((a, i) => (
<li key={i}>
{a}{" "}
<button type="button" onClick={() => deleteItem(i)}>
Delete
</button>
</li>
))}
</ul>
</div>
);
};
export default App;
我开始在空闲时间学习 React。启动 Hooks 时,会调用两次 setState 方法。 实时代码在
https://codesandbox.io/s/elastic-saha-mdwwc?file=/src/App.js
当我按 enter 键时,添加按钮起作用 fine.But,setState 函数被调用两次。最初的想法是内容重新 rendered.But 我将 useEffect 依赖项作为一个空数组。所以没有重新渲染,我不知道如何调试它。感谢您的帮助:)
const App = () => {
const [text, setText] = useState('');
const [list, setList] = useState([]);
const addToList = () => {
if (text !== '') {
setList([...list, text]);
setText('');
}
}
const deleteItem = index => {
const deletedList = list.filter((_, i) => i !== index);
setList(deletedList)
}
useEffect(() => {
console.log("Reloaded");
const listener = e => {
if (e.code === 'Enter') {
console.log("event triggered")
setText(text => {
if (text !== '') {
console.log("updating")
setList(a => ([...a, text]));
}
return ''
});
}
}
document.getElementById('textbox').addEventListener('keyup', listener);
console.log('Event registered')
return () => {
document.getElementById('textbox').removeEventListener('keyup', listener);
console.log('Event deregistered')
}
}, [])
return (
<div >
<input type="text" id="textbox" onChange={(e) => setText(e.target.value)} value={text} />
<button id="add" onClick={addToList}> Add</button>
<ul>
{
list.map((a, i) => <li key={i}>{a} <button type="button" onClick={() => deleteItem(i)}>Delete</button></li>)
}
</ul>
</div>
);
}
export default App;
我认为这是因为您代码中的 useEffect
:
setText(text => {
if (text !== '') {
console.log("updating")
setList(a => ([...a, text]));
}
return ''
});
将其更改为以下内容:
useEffect(() => {
console.log("Reloaded");
const listener = (e) => {
if (e.code === "Enter") {
console.log("event triggered");
if (text !== "") {
console.log("updating");
setList((a) => [...a, text]);
}
return "";
}
};
document.getElementById("textbox").addEventListener("keydown", listener);
console.log("Event registered");
return () => {
document
.getElementById("textbox")
.removeEventListener("keydown", listener);
console.log("Event deregistered");
};
}, [text]);
或者,
useEffect(() => {
console.log("Reloaded");
const listener = (e) => {
if (e.code === "Enter") {
console.log("event triggered");
if (e.target.value !== "") {
console.log("updating");
setList((a) => [...a, e.target.value]);
}
e.target.value = "";
return "";
}
};
document.getElementById("textbox").addEventListener("keydown", listener);
console.log("Event registered");
return () => {
document
.getElementById("textbox")
.removeEventListener("keydown", listener);
console.log("Event deregistered");
};
});
或者,
这个使用了onKeyPress
事件并且在挂载组件时只运行useEffect
一次
import React, { useState, useEffect } from "react";
const App = () => {
const [text, setText] = useState("");
const [list, setList] = useState([]);
const addToList = () => {
if (text !== "") {
setList([...list, text]);
setText("");
}
};
const deleteItem = (index) => {
const deletedList = list.filter((_, i) => i !== index);
setList(deletedList);
};
const listener = (e) => {
e.stopPropagation();
if (e.key === "Enter") {
console.log("event triggered");
if (text !== "") {
console.log("updating");
setList((a) => [...a, text]);
}
setText("");
return "";
}
};
// not needed, only here to show it only runs once
useEffect(() => {
console.log("Reloaded");
}, []);
return (
<div>
<input
type="text"
id="textbox"
onChange={(e) => setText(e.target.value)}
onKeyPress={listener}
value={text}
/>
<button id="add" onClick={addToList}>
{" "}
Add
</button>
<ul>
{list.map((a, i) => (
<li key={i}>
{a}{" "}
<button type="button" onClick={() => deleteItem(i)}>
Delete
</button>
</li>
))}
</ul>
</div>
);
};
export default App;