在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 />)
相关推荐
吃乔巴的糖13 小时前
Vue 3 打印模板设计器 (print-canvas-designer)
前端·vue.js
如果超人不会飞17 小时前
后端别再手绘了!TinyVue 流程图组件 Flowchart 跨端定制指南
vue.js
cc.ChenLy18 小时前
大文件断点续传原理总结和Demo示例详解
javascript·vue.js·文件上传·大文件断点续传
程序员祥云18 小时前
VUE2_TO_VITE_VUE3
javascript·vue.js·ecmascript
苏瞳儿18 小时前
vue3+pinia+mqtt实时响应连接
前端·javascript·vue.js
i220818 Faiz Ul19 小时前
理财系统|基于java+vue的家庭理财系统小程序(源码+数据库+文档)
java·vue.js·spring boot·小程序·论文·毕设·理财系统
暗冰ཏོ19 小时前
《2026 Vue2 + Vue3 完整学习指南:基础语法、路由缓存、登录拦截、项目实战与面试题》
前端·vue.js·vue·vue3·vue2
kyriewen19 小时前
14MB VS 15KB:前React核心成员用AI写了个排版库,让Safari快了一千倍
前端·javascript·react.js
幸运小圣19 小时前
动态表格在 Vue 3 中的实现指南【前端】
前端·javascript·vue.js
SwJieJie20 小时前
Day 3|表格表单分页范式与 vue-request 最佳实践:从配置驱动到业务落地
前端·javascript·vue.js