面试题答案
一键面试createSignal 依赖收集与触发更新原理
- 依赖收集
- 在 Solid.js 中,
createSignal
创建一个信号(包含值和更新函数)。当组件渲染时,若访问了信号的值,Solid.js 会在内部将当前组件的渲染函数注册为该信号的依赖。这是通过一个全局的“追踪”机制实现的。例如,在组件函数内部,当执行const [count, setCount] = createSignal(0);
后,若使用count()
来获取值,Solid.js 会记录下当前组件函数对count
信号的依赖。
- 在 Solid.js 中,
- 触发更新
- 当调用
createSignal
返回的更新函数(如setCount
)时,Solid.js 会遍历该信号所收集的依赖列表(即依赖此信号的组件渲染函数列表)。对于每个依赖,Solid.js 会重新运行该组件的渲染函数,从而实现视图更新。例如,调用setCount(1)
时,依赖count
信号的组件会重新渲染,展示新的值。
- 当调用
复杂数据结构下依赖追踪示例
- 嵌套对象
import { createSignal } from "solid-js"; import { render } from "solid-js/web"; const App = () => { const [data, setData] = createSignal({ user: { name: "John", age: 30 } }); const updateAge = () => { setData((prevData) => { return { ...prevData, user: { ...prevData.user, age: prevData.user.age + 1 } }; }); }; return ( <div> <p>Name: {data().user.name}</p> <p>Age: {data().user.age}</p> <button onClick={updateAge}>Increment Age</button> </div> ); }; render(() => <App />, document.getElementById('root'));
- 在上述代码中,
data
是一个包含嵌套对象的信号。当updateAge
函数更新data
信号时,Solid.js 能够追踪到对data().user.age
的依赖,重新渲染包含该依赖的组件部分。这是因为 Solid.js 基于对象的引用变化来判断依赖。当setData
返回一个新的对象引用(通过展开运算符创建新对象),Solid.js 会重新运行依赖该信号的组件渲染函数,使得视图能展示更新后的age
值。
- 在上述代码中,
- 嵌套数组
import { createSignal } from "solid-js"; import { render } from "solid-js/web"; const App = () => { const [list, setList] = createSignal([ { id: 1, name: "Item 1" }, { id: 2, name: "Item 2" } ]); const updateItem = () => { setList((prevList) => { return prevList.map((item) => { if (item.id === 1) { return { ...item, name: "Updated Item 1" }; } return item; }); }); }; return ( <div> <ul> {list().map((item) => ( <li key={item.id}>{item.name}</li> ))} </ul> <button onClick={updateItem}>Update Item 1</button> </div> ); }; render(() => <App />, document.getElementById('root'));
- 这里
list
是一个包含对象的数组信号。当updateItem
函数更新list
信号时,Solid.js 通过检测数组引用的变化(由于map
返回了一个新数组),重新运行依赖list
信号的组件渲染函数。这样,视图中展示的列表项会根据更新后的数据进行相应的更新,实现了对嵌套数组结构的有效依赖追踪。
- 这里