SolidJS中每次变更时列表项均重新挂载是否正常?
SolidJS列表项每次变更都重新挂载是否正常?
这种情况不正常,SolidJS的<For>组件设计初衷就是实现列表的高效更新,避免不必要的组件重挂载,问题出在你的数据更新方式上。
问题原因
- 每次点击按钮时,你通过
users.map(user => ({...user, name: 'Suzy'}))生成了全新的数组和每个用户对象。<For>组件依赖数据的引用稳定性来追踪列表项,当所有项的引用都发生变化时,它会判定所有列表项都是新的,因此会卸载旧的Card组件,重新挂载新的实例,这就导致console.log('card')每次点击都会执行。 - 改用
createStore后如果还是用同样的方式替换整个对象引用,结果也会一致,因为<For>依然会把新引用识别为新的列表项。
解决方案
1. 细粒度更新数据(推荐)
使用createStore支持的细粒度更新,直接修改对象属性而不替换整个对象或数组:
import { Component, For } from 'solid-js'; import { createStore } from 'solid-js/store'; const data = [ {name: 'Helen'}, {name: 'Peter'}, {name: 'Maksim'}, ] const Card: Component<{name: string}> = (props) => { console.log('card'); // 仅在第一次挂载时执行 return <div> <span>Name: </span> <span>{props.name}</span> </div> } export const App: Component = () => { const [users, setUsers] = createStore(data); return ( <> {/* 直接更新每个用户的name属性,不改变对象引用 */} <button onClick={() => setUsers(() => ({ name: 'Suzy' }))}>Click</button> <For each={users}>{user => <Card name={user.name} />}</For> </> ); };
这种方式下,<For>会识别到只是列表项的属性变化,而非项本身被替换,因此只会更新Card组件内对应的DOM部分,不会重新挂载整个组件。
2. 保持数据引用稳定性
如果必须生成新对象,确保列表项的引用尽可能稳定,只更新需要变化的部分。比如仅修改单个用户的属性时,不要替换整个数组,只更新目标对象的属性。
补充说明
正常情况下,当仅变更组件props的属性值而非props的引用时,SolidJS只会更新组件内对应的DOM节点,不会重新执行组件的初始化代码(即console.log只会在组件第一次挂载时运行)。
内容的提问来源于stack exchange,提问作者foloin
相关产品推荐
相关产品推荐

