StackOverflow 上的第一篇文章。很高兴认识你!
我正在尝试从 React 书中实现一个简单的整体应用程序,但我偶然发现了一个我无法解释的行为。我想请求您帮助理解为什么会发生这种情况。该示例是一个设计不佳的应用程序,稍后将其分解为可重用的组件。
当我在输入字段“标题”中键入任何字符时,onChangeTitle 事件将按预期调用。但在事件执行后,“articles”的 useState(位于 MyFeature() 函数定义的顶部)也会被调用,每次在“Title”中键入一个字符时,都会一次又一次有效地执行“id”函数。 “ 输入字段。
我已经调试了代码,似乎执行到了“MyFeature”的顶部,并向下移动了 setState 调用,但只有“文章”和“标题”的状态发生了变化。我期望整个 MyFeature 被重新渲染,但我没想到会调用“articles”setState 挂钩,因为它的值没有改变。知道为什么会发生这种情况吗?
谢谢您的帮助!
马可
import { useState, useCallback } from 'react';
const id = (function* () {
let i = 1;
while (true) {
console.log(i);
yield i;
i += 1;
}
})();
function MyFeature() {
const [articles, setArticles] = useState(
[
{
id: id.next(),
title: "Article 1",
summary: "Article 1 summary",
display: "none"
},
{
id: id.next(),
title: "Article 2",
summary: "Article 2 summary",
display: "none"
}
]
);
const [title, setTitle] = useState("");
const [summary, setSummary] = useState("");
const onChangeTitle = useCallback((e) => {
setTitle(e.target.value);
}, []);
const onChangeSummary = useCallback((e) => {
setSummary(e.target.value);
}, []);
const onClickAdd = useCallback(() => {
setArticles((state) => [
...state,
{
id: id.next(),
title: title,
summary: summary,
display: "none",
},
]);
setTitle("");
setSummary("");
}, [summary, title]);
const onClickRemove = useCallback((id) => {
setArticles((state) => state.filter((article) => article.id !== id));
}, []);
const onClickToggle = useCallback((id) => {
setArticles((state) => {
const articles = [...state];
const index = articles.findIndex((article) => article.id === id);
articles[index] = {
...articles[index],
display: articles[index].display ? "" : "none",
};
return articles;
});
}, []);
return(
<section>
<header>
<h1>Articles</h1>
<input placeholder="Title" value={title} onChange={onChangeTitle} />
<input placeholder="Summary" value={summary} onChange={onChangeSummary} />
<button onClick={onClickAdd}>Add</button>
</header>
<article>
<ul>
{articles.map((i) => (
<li key={i.id.value}>
<a href={'#${i.id}'} title="Toggle Summary" onClick={() => onClickToggle(i.id)}>{i.title}</a>
<button href={'#${i.id}'} title="Remove" onClick={() => onClickRemove(i.id)}>✗</button>
<p style={{ display: i.display }}>{i.summary}</p>
</li>
))}
</ul>
</article>
</section>
);
}
export default MyFeature;
每次重新渲染时,函数的代码都会运行,因此由于函数的工作方式,
useState
初始化程序不可能不运行。然而,useState
确实有一个变体,可以让您指定一个函数,而不是仅在第一次初始化状态时运行的value
。
const [articles, setArticles] = useState(() => [
{
id: id.next(),
title: "Article 1",
summary: "Article 1 summary",
display: "none"
},
{
id: id.next(),
title: "Article 2",
summary: "Article 2 summary",
display: "none"
}
]);