在react中使用signal

我参考solid的语法 完成了一个能在react里使用signal的npm包

曾经考虑过使用vue或preact的独立reactivity包 但考察过后发现不太符合需求 所以内部实现都是自己完成的

API

提供了与solid很相似的api

  • createSignal 创建signal
ts 复制代码
const [count, setCount] = createSignal(0)
// 正常访问signal
count()
// 不具有响应性的访问
count.value
  • createMemo 创建派生signal.同样可以通过.value方式访问值
  • defineComponent 定义组件.
tsx 复制代码
type CompProps = {
  // 组件参数可以是signal
  num: () => number
}
const Comp = defineComponent<CompProps>((props) => {
  // props对象是signal 返回一个render函数
  // render中用到的signal被自动收集 变化后更新组件
  return () => <span>{props().num()}</span>
})
  • createEffect 创建一个副作用 它会在useEffect阶段被执行 与组件渲染强相关
  • createRef 创建一个react ref 可以直接用在html属性上
  • onCleanup 可以为组件 createMemo createEffect提供清理函数

说明

暂时不适配热重载

使用例

tsx 复制代码
import ReactDOM from 'react-dom/client'
import {
  defineComponent,
  createEffect,
  createMemo,
  createSignal,
  onCleanup,
  createRef,
} from '@fane_the_divine/react-signal'

const Page = defineComponent(() => {
  // 验证基本的响应式能力
  const [count, setCount] = createSignal(0)
  const spanRef = createRef<HTMLSpanElement>()
  const double = createMemo(() => {
    console.log(spanRef.current)
    onCleanup(() => console.log('memo cleanup', count.value))
    return count() * 2
  })
  createEffect(
    (_, isFirst) => {
      console.log(`effect: isFirst:${isFirst} `, spanRef.current)
      onCleanup(() => console.log('cleanup in effect'))
    },
    [double],
  )
  const [show, setShow] = createSignal(true)
  return () => {
    console.log('render')
    return (
      <>
        <button
          onClick={() => {
            setCount(count() + 1)
            setCount(count() + 1)
          }}
        >
          {count()}
        </button>
        <span ref={spanRef}> {double()}</span>
        <button onClick={() => setShow(!show())}>{show() ? 'hidden' : 'show'}</button>
        {show() ? <SubComp1 value={count} /> : null}
      </>
    )
  }
})

const SubComp1 = defineComponent<{ value: () => number }>((props) => {
  // 验证组件销毁后的cleanup被执行
  createEffect(() => {
    onCleanup(() => console.log('SubComp1 unmount in effect'))
  })
  onCleanup(() => console.log('SubComp1 unmount'))
  return () => {
    console.log('%csub comp1 render', 'font-size: 28px; font-weight: bold; color: blue;')
    return <SubComp2 value={props().value} />
  }
})
const SubComp2 = defineComponent<{ value: () => number }>((props) => {
  // 验证signal跨层不重新渲染的能力
  return () => {
    console.log('%csub comp2 render', 'font-size: 28px; font-weight: bold; color: red;')
    return <button>sub comp2 {props().value()}</button>
  }
})
ReactDOM.createRoot(document.getElementById('root')!).render(<Page />)
相关推荐
雪芽蓝域zzs5 小时前
第 2 节:基础扩展 - 下拉弹窗常用原生属性
vue.js·elementui
xxwl58516 小时前
vue3的入门学习
前端·vue.js·学习
web打印社区16 小时前
政务办事大厅:叫号小票、办理回执网页怎么静默出纸
前端·javascript·vue.js·pdf·html·政务
斯内普吖17 小时前
(开源)水果蔬菜商城实战指南 基于 Java + SSM + Vue + MySQL
java·vue.js·mysql·开源
ss27318 小时前
AI全栈实战 | 2.2-02 React 思维模型:数据不可变 vs Vue 数据可变,两种哲学把复杂度推给谁
前端·vue.js·react.js
天衍四九-18 小时前
Docker Compose企业实战系列(三):Vue/React前端项目容器化完整部署
前端·vue.js·docker
墨鱼老师18 小时前
SpringBoot+Vue 毕设项目开发踩坑记录(前后端分离)
vue.js·spring boot·毕业设计·课程设计·前后端分离·java 毕设
雪芽蓝域zzs19 小时前
Vue3 + Element Plus el-select 下拉弹窗
vue.js·elementui
Wx-bishekaifayuan19 小时前
springboot房屋租赁系统11574-计算机课程设计、毕业设计
java·vue.js·spring boot·后端·sql·spring·课程设计