当我重现 useState setter 函数和
$0.click();$0.click();
发生的错误时,我意识到不一致的行为并且无法在网上找到答案。所以就在这里。
APP
import Accordion from "./components/Accordion";
function App() {
const items = [
{
id: "asfgasf",
label: "Can I use React on a project?",
content: "You can use React on any project you want.",
},
{
id: "sadsad",
label: "Can I use JS on a project?",
content: "You can use React on any project you want.",
},
{
id: "wdasdw",
label: "Can I use CSS on a project?",
content: "You can use React on any project you want.",
},
];
return <Accordion items={items} />;
}
export default App;
手风琴组件
function Accordion({ items }) {
const [expandedIndex, setExpandedIndex] = useState(-1);
const handleClick = (index) => {
console.log("STALE", expandedIndex);
setExpandedIndex((current) => {
console.log("UPDATED", current);
return current === index ? -1 : index;
});
console.log("CALLED AFTER SETTER FUNCTION");
};
const renderedItems = items.map((item, index) => {
const isExpanded = index === expandedIndex;
return (
<div key={item.id}>
<div onClick={(e) => handleClick(index, e)}>{item.label}</div>
{isExpanded && <div>{item.content}</div>}
</div>
);
});
return <div>{renderedItems}</div>;
}
export default Accordion;
对于第一次点击事件,我得到了这个同步日志(我觉得很奇怪):
STALE -1
UPDATED -1
CALLED AFTER SETTER FUNCTION
在每次点击变化的第一次点击事件之后,我得到异步日志,其中“设置函数后调用”方法在“更新”日志之前打印出来:
STALE **someValue**
CALLED AFTER SETTER FUNCTION
UPDATED **someValue**
我想了一会儿,出于某种原因,它可能是为第一次点击事件而设计的。但问题是,每当我在控制台上用
$0.click();$0.click();
触发点击事件时,在这些点击事件的日志之后,我第一次单击“div”我会返回同步日志。奇怪的是,如果我触发带有$0.click();$0.click();
的点击事件进行偶数次点击,我会得到同步行为,如果我触发奇数次点击事件,例如 $0.click();$0.click();$0.click();
,我得到异步行为。我尝试了 3、5、7、9 奇数和 2-4-6-8 偶数。结果都一样。在控制台上触发偶数之后,首先每次我点击一个 div,任何 div,在控制台触发奇数次点击事件后,我会得到同步日志和正常的异步行为。
是的,我试图重现一个错误并面临不一致的行为,但是由
$0.click();$0.click();
引起的已知错误非常清楚。我们没有将函数传递给setter函数,而是传递了一个硬编码值并创建了两个发送到回调队列的执行上下文相同,因此事情不会按预期工作。但这里的相同功能在奇数次快速点击后以异步方式起作用,而在偶数次点击后以同步方式起作用。除了初始渲染后的第一次点击,这对我来说也很奇怪。
我有点为此失眠,我将不胜感激任何解释。
提前致谢。