React输入框onChange触发时意外调用articles的useState问题求助
问题原因与解决方案
核心原因
React组件每次重新渲染时,组件函数会完整执行一遍,包括useState的初始值表达式。你在articles的useState初始值中直接调用了id.next(),所以每次组件因title/summary状态变化重新渲染时,这两个id.next()都会被执行,导致生成器不断推进,输出新的i值。
注意:useState的初始值只会在组件首次挂载时被用来初始化状态,但初始值表达式本身在每次渲染时都会执行——React会忽略首次挂载后的初始值,但表达式的执行是无法避免的。
修复方案
方案1:用useMemo缓存初始articles数组
把初始articles的创建逻辑包裹在useMemo中,依赖项设为空数组,确保只在组件首次渲染时执行一次:
import { useState, useCallback, useMemo } from 'react'; const id = (function* () { let i = 1; while (true) { console.log(i); yield i; i += 1; } })(); function MyFeature() { // 用useMemo缓存初始数组,仅首次渲染执行 const initialArticles = useMemo(() => [ { 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 [articles, setArticles] = useState(initialArticles); // ... 其余代码不变 }
方案2:直接初始化固定id(更简单)
如果初始文章的id不需要动态生成,直接写死固定值,仅在新增文章时调用生成器:
function MyFeature() { const [articles, setArticles] = useState([ { id: { value: 1 }, // 直接写死初始id title: "Article 1", summary: "Article 1 summary", display: "none" }, { id: { value: 2 }, title: "Article 2", summary: "Article 2 summary", display: "none" } ]); // ... 新增时依然用id.next() }
额外注意点
你的生成器id.next()返回的是IteratorResult对象(结构为{ value: 数字, done: 布尔值 }),在删除文章的逻辑中,onClickRemove里的判断article.id !== id其实是在比较对象引用,应该改为比较article.id.value !== id.value,否则删除功能会失效:
const onClickRemove = useCallback((id) => { setArticles((state) => state.filter((article) => article.id.value !== id.value)); }, []);
内容的提问来源于stack exchange,提问作者Marco Monteiro
相关产品推荐
相关产品推荐

