【发布时间】:2020-10-28 20:38:06
【问题描述】:
我有以下场景:
DisplayList 组件,它呈现一个列表。列表记录通过 props 传入(这包含列表名称、描述、作者等),以及要列出的初始项目,以及当前的“模式”(可以是 'r'、'g' 或 'a' )。该组件显示列表信息,然后为每个列表项呈现一个DisplayItem 组件。 DisplayItem 组件还带有一个回调函数,这样当用户点击列表中的一个项目时,它就会被当前模式“标记”(即项目的“模式”属性发生变化)。
const DisplayList = (props) => {
// Get list object (contains list name etc)
// and current mode (r, a or g)
const { list, currentMode } = props
// Array of items to show
// This is an array of objects, with each object representing a single item
// eg {name: itemname, mode: r}
const [ items, setItems] = useState(props.items)
// Callback function - triggered when the rendered DisplayItem is clicked
// This changes the 'mode' of the item to the current mode
function handleItemClick(index) {
items[index].mode = currentMode
setItems(items) // At this point the list of items should re-render
}
}
return (
<div className="displayItem">
{
items.map(item => <DisplayItem key={uuid()} item={item} handleCellClick={handleItemClick} />)
}
</div>
)
}
我遇到的问题是单击一个项目似乎会触发 handleItemClick 函数来更新 itemList,但是当它到达 setItems 时,它不会重新渲染。
【问题讨论】:
-
不是一个直接的答案,但是每次渲染生成一个 uuid 用作键是没有意义的。如果您没有唯一标识符来重用每个渲染,请使用数组索引。
-
更直接的答案:
items[index].mode = currentMode改变状态并将原始数组引用传递给更新函数,这意味着无论您更新多少嵌套值,react 都不会将其视为更改。在变异之前创建一个新的状态副本,然后给更新函数提供 new 数组。 -
Brian 是正确的,您只需要创建一个新数组即可。但是您应该使用 uuid,使用数组索引是一种不好的做法。它会减慢您的应用程序并导致问题,因为您不能保证一个项目将始终具有相同的索引。最佳实践是给每个项目一个唯一的 id 并使用它,但 uuid 比 index.html 更好。 stackoverflow.com/questions/46735483/…
-
@nzajt 不,这绝对不是一个更好的做法。在渲染期间生成一个 uuid 作为 key 是没有意义的。React 使用 key 来区分组件实例以进行后续更新、卸载等。这意味着如果一个元素在每次渲染时都获得一个新的 key,react 会将其视为 new 组件实例并将重新安装元素。如果您的元素是具有状态的组件,您将发现错误,因为状态将重置并且生命周期方法将重新启动。 如果您没有唯一标识符,则可以使用索引。这是 react 默认做的,但并不理想。
-
请参阅this answer,了解使用 uuid 作为键的正确方法,同时在渲染期间生成它不会影响性能。