@fane_the_divine/react-signal
v0.0.3
Published
在react中使用signal
Maintainers
Readme
react-signal
在react里使用signal
API参考solid,使用方法见demo.
npm i @fane_the_divine/react-signal使用时可能出现hmr失效的问题,需要重建组件或刷新网页
API介绍
createSignal
创建signal
const [count, setCount] = createSignal(0)
// 使用signal
count()
// 不具有响应性地获取signal里的值
count.value可以在任何位置使用createSignal
defineComponent
type CompProps = {
num: () => number
}
const Comp = defineComponent<CompProps>((props) => {
// props对象是signal 参数也是signal
return () => <span>{props().num()}</span>
})defineComponent接受一个setup函数 这个函数在组件整个生命周期内只执行一次 setup应当返回一个render函数 这个函数会执行多次
createMemo
创建一个派生signal
// 参数为上一次的memo值
const double = createMemo((prev) => {
return count() * 2
})
// 访问其值
double()
// 不具有响应性地获取其值
double.value可以在任何位置使用createMemo
派生signal会记录当前值是否过期 直到值被访问的时候才实际进行计算
createEffect
创建基于signal的副作用,它们在react的useEffect阶段执行
defineComponent(() => {
createEffect(
// 允许effect函数返回一个值 并会输入到下一次effect函数
// 可以从参数判断是否第一次调用
(prev, isFirst) => {
// 以非.value方式使用的signal会被收集 在其变化后 触发副作用
signal1()
return (prev ?? 0) + 1
},
// 允许提供一个signal数组作为额外的依赖
[signal2],
{
// 在useLayoutEffect阶段执行副作用
layoutEffect: true,
},
)
})createEffect应当在defineComponent内部调用
关于它的清理函数 参考下一节
onCleanup
提供清理函数
defineComponent(() => {
createMemo(() => {
onCleanup(() => console.log('memo cleanup'))
})
createEffect(() => {
onCleanup(() => console.log('effect cleanup'))
})
onCleanup(() => console.log('component cleanup'))
})onCleanup可以在defineComponent createMemo createEffect内部调用 作用不同
- 在defineComponent内调用时 cleanup函数在组件销毁后调用
- createEffect/createMemo内调用时 cleanup会在effect/memo函数调用前调用
createRef
创建一个react ref
defineComponent(() => {
const spanRef = createRef<HTMLSpanElement>()
return () => <span ref={spanRef} />
})不提供参数时 类型是RefObject<T|null> 可以直接用到html上
实现原理简述
在reactivity.ts定义了响应式作用域和组件作用域相关内容.
通过全局变量的方式,可以注册一个响应式作用域。在它内部使用的signal变化后,响应式作用域可以感知这一变化并做出反应。例如组件会更新,派生signal将自身标记为已过期等。响应式作用域还可以感知内部的onCleanup调用,收集清理函数,并在自身销毁时调用清理函数。
组件作用域同样通过全局变量实现,它可以让函数在本组件的下一次useEffect阶段调用被调用.
defineComponent会创建响应式作用域和组件作用域。它会收集setup函数中的onCleanup调用,以及render函数中对signal的使用。
createMemo会创建响应式作用域。它不会立刻调用memo函数,而是在signal()或signal.value时才实际计算值。在memo函数执行后,它会收集其使用到的signal,每次memo函数执行前都会清空上次收集的signal。在其依赖的signal变化后,它将自身标记为已过期,并向所有使用自身的响应式作用域发消息。
createEffect在依赖收集方面与createMemo类似。在副作用实现上,createEffect确保函数callEffectFn在每个useEffect都执行。这个函数会访问shouldCallEffect变量,它为true时再执行effect函数,然后将此变量置为false。每当createEffect包裹的signal变化时,shouldCallEffect被置为true。
onCleanup获取当前的响应式作用域并将增加其清理函数。
createRef返回了一个普通对象。
