SolidJS
逻辑
条件类名
<div class={`w-full max-w-2xl transition-all duration-300 ${isSearching() ? 'self-start' : ''}`}>
响应式数据
createSignal
适用于简单数据,以及仅用于展示的复杂数据(数组、对象)。
Signal的响应式,是整体的响应式,要改就全改。
const [zhangsan, setZhangsan] = createSignal({
name: '123',
age: 16
});
// 必须修改整体
setZhangsan({
name: '123',
age: 19
})
- 外部元素
(如 list()[0].name):直接依赖 list 信号的整体引用,每次 setList 调用(即使返回修改后的新数组)会触发外部依赖更新。 - For 内部元素
For 组件会为每个列表项创建独立的响应式上下文。如果直接修改数组元素而不创建新引用,Solid.js 可能无法检测到子项的变化,因为For 的依赖追踪基于数组的整体引用和子项的引用。
直接修改对象属性(如 item.name)不会触发 For 的重新渲染,因为子项对象的引用未变。
在日常使用中,是否使用For取决于排版需要,他是灵活的,容易变的。因此应该时刻满足上述For的依赖更新要求,以降低心智负担(也就是不要到了用到For的时候才想到要满足这种条件)。于是乎,应该满足以下条件:
- 整体的引用应当是一个新的引用。(createSignal的要求)
- 修改了的数据区域中,如果有数据是一个复杂对象(比如数组或者{}对象),那么更新这个数据时,应当创建一个新的引用。
于是得到下面这样诡异的代码。
setList((prev) => {
// 内部对象赋值为新的引用
prev[0] = {...prev[0], name: e.currentTarget.value};
// 对Signal整体创建一个新的引用
return [...prev];
});
createStore
适用于复杂数据,可以细粒度响应式,性能开销更大一些。
如果一段列表数据,每个元素是一个卡片,并配有一个编辑按钮,当点击编辑时卡片中的数据可以修改。页面也发生变化。
- 由于卡片列表来自API,所以数量不确定,因此
是否可编辑这个变量应该和每个卡片元素绑定,而卡片列表是一个信号量。 - 页面使用Show进行条件渲染,判断条件是
card().isEditing
由于Signal的属性是不响应的,因此按编辑按钮后一点响应也没有。此时我们只好使用createStore。
如果使用弹窗,可以用多个Signal将多个属性临时存放实现响应式。然而此处的核心在于条件渲染无法正常触发,因此在。
参数传递
状态提升(props传递)
export default function Index() {
const [isOpen, setIsOpen] = createSignal(false);
const [description, setDescription] = createSignal("");
const [category, setCategory] = createSignal("");
// 传递给 Site 的回调函数
const handleSiteButtonClick = (data: { description: string; category: string }) => {
setDescription(data.description);
setCategory(data.category);
setIsOpen(true);
};
return (
<div>
<Site onButtonClick={handleSiteButtonClick} />
<Dialog
isOpen={isOpen()}
onClose={() => setIsOpen(false)}
description={description()}
category={category()}
/>
</div>
);
}
缺点很明显,如果有多个组件,那么这些变量就总是需要传递。
适用于关系较为简单的组件。
优势:没有额外的抽象概念。
Provider/Context
安卓里面也有这玩意,原理就是树上直接传递上下文,默认就把上下文带着。(而props需要手动写)
缺陷:每个组件都需要引入context依赖。

写起来很繁琐。
建议创建响应式数据和定义Context放在一起,把Provider写成一个独立组件。
因为Provider的values需要传递参数。如果要添加一个参数,你需要
- 新增一个createSignal信号量
- 在DialogContextType中添加一个字段类型
- 在Provider的value中,将其传入
如此重复繁琐的工作,如果代码还不在一块,那真是烦死了。
恶心的点在于,Provider这一层不能使用context,哪怕包在最外面。
也就是说,你不能在父组件中使用context。
这意味着,如果想把数据存在Provider封装组件中,应当把Provider套在父组件外面,才能在父组件中访问数据。
于是乎得到这样的套娃情况,因为在当前Index组件中无法获取context,只能套一层。

参数传递总结
- props
除非特别简单的参数,否则不用考虑。万一要改一下层级直接爆炸。
props适合需求固定的场合(比如组件库),他的最大优点就是容易理解,依赖少。
-
context
Context适用于父子之间,但是他可以层层传递。比如我们把一个页面中的Context作为一个数据源。
context只能在组件中使用,无法拆分到ts文件中。 -
store
最全能的选手,完美解决状态管理问题。
只要不拆组件,那么就不用传递参数了

浙公网安备 33010602011771号