npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

limbo-reactivity

v1.0.2

Published

一个数据驱动的响应核心

Downloads

2

Readme

reactivity

一个数据驱动的响应核心

本仓库并不提供独立的dom操作库,只提供连接符合dom接口(react标准)规范的dom库的嵌入api。

如果你想使用现成的框架,可以移步limbo(一个集成了调度和事件系统的高性能现代前端框架)。并且使用我们提供的mixInReact来注册limbo

如果你想使用符合规范的其他框架,请使用reactivity/register进行注册。

当然,最方便的还是使用我们提供的reabo来作为独立的mvvm框架使用。(实际上,它就是通过reactivity/register注册了limbo)

install

yarn add @limbo/reactivity

HOW TO USE

注意: reactivity本身可以以一个完整的mvvm框架形态使用,并且提供了高性能的独立diff包及一些静态优化,但我们还是希望用户能使用标准的react生态,所以独立dom需要引入额外的插件.

mixInReact

要想在react里使用reactivity是非常简单的,只需要使用两行代码

import { mixInReact } from '@limbo/reactivity'
mixInReact(React)

从此,你可以快乐的在React里使用reactivity了.

rootState

默认的,reactivity会为每一个React.Component注入一个名为rootState的对象,你可以直接操作这个对象上的任意值,并会直接得到响应

const A = (props) => {
    const handleClick = () => {
        props.rootState.a += 1
    }
    return (
        <button onClick={handleClick}></button>
    )
}

上面代码中,点击了按钮后,任何依赖rootState.a的组件都会更新

createState

你可能会问,rootState究竟从哪里来呢? reactivity提供了一个注册rootState的方法

setRootState(
    createState({
        a:1,
        b:2,
        c:{d:[1,2,3],e:1},
        f:{a:1,b:2}
    })
)

事实上,createState注册了一个reactivity概念上的State,然后通过 setRootState将它注册到rootState上.

createRef

当然,如果你想像vue3一样创建一个单值属性,你也可以使用createRef

注意,你需要使用value来访问它。具体的,你可以参考call by valuecall by reference的区别。

function App() {
    const ref = createRef(1)
    useEffect(() => {
        console.log(ref.value)
    })
    return <Son state={ref}/>
}

createWatcher

作为响应式框架,watcher应该是很常见的功能。 它随着一个响应式变量的更新而触发提前定义好的响应操作。

function App() {
    const state = createState({
        userId: 'init'
    })
    const watch = createWatcher(state,'userId',(newState,oldId,newId) => {
        localStorage.setItem('id',newId)
    })
}

createWatcher的签名如下:

watcher:(state:State,key:any,onChange:IOnChange)
IOnChange:(newState: object, oldValue ?: any, newValue ?: any, changeKey ?: any) => void

createCompued

同时,reactivity提供了计算功能,你可以像任何响应式框架(vue,mobx)一样使用computed

function App(props) {
    const computed = createComputed(() => props.state.a * props.state.b)
}

注意,createComputed需要传入一个函数

anyState

是的,单一的rootState非常难以管理,我们希望在任何位置都能快速的创建一个 State,并提供响应式的能力,参考以下代码:

function App(props) {
  const A = createState({aa:1})
  return (
    <OtherState otherState={A}/>
  )
}

此时,你可以在OtherState里直接修改A的任意值,它也会触发响应式更新.

computed

watcher

当你在注册一个State时,实际上就是对一个object进行观察,同时reactivity也暴露出了一个watcher的API

let obj = {a:1,b:2}
obj = watcher(obj,() => console.log('i am not side-effect'))

修改

你可以对任意的State(不论是自动注入,或是手动创建的)进行修改.

Array

const A = createState([1,2,3])
A.length = 4
A[2] = 0
A.push(3)

上面的每一项都会触发响应式的更新,无需其他的心智负担.

nest-object

同样的,即使在深层次的嵌套对象的情况下,它也会完美的进行响应.

const A = {
    a: {
        b: {
            c
        }
    }
}
A.a.b.c = 3

性能

one but only one update once

reactivity保证了当父子组件都需要更新的时候,但子组件先于父组件更新时,父组件不会再无效的reconcile子组件。

如何定义无效更新

实际上,父组件传入的props不发生变化时,子组件不应该出现任何由父组件更新导致的变化。所以reactivityshallowequal作为是否有效更新的判断标准。

更新顺序

实际上,更新顺序在开启schedule后是由react决定的,父子组件在updateQueue中的位置并不由reactivity计算,但框架保证了必要情况下节省无效更新。

内存泄露

reactivity拥有非常好的依赖收集性能,它没有潜在的引用逃逸和闭包等问题, 旧的依赖都会在下次收集时被清除,无需担心依赖储存会导致内存泄漏.

依赖收集

很不幸的是,目前的响应式框架都存在非常大的问题: 轻量级的依赖收集在组件规模增大后,却会成为一个非常耗时的工作.

reactivity并没有办法解决它,但是有很多小技巧可以提升依赖收集过程的性能 .一个很常见的方法就是,不要使用嵌套层级太深的数据结构作为State,你应该打平而不是嵌套他们.

// good
const A = createState({a:1})
const B = createState({b:2})
const C = createState({c:3})

// bad
const nest = createState({a:{b:c}})

原因在于,你可以在任何地方创建State,所以对嵌套对象的依赖就没有那么必要了.

依赖清除

上面已经提到过,依赖清除会在第二次收集时进行.它的实现是标准的double buffer,具体细节不必深究.

React生态

自动优化

在集成reactivity后,你的React应用不再需要使用繁琐的memo或者PureComponent来进行优化了,任何组件都会被自动的shallowEqual优化.

精确更新

使用响应式框架最诱人的一点就是,你不再需要使用redux里繁琐的reselect来进行性能提升,也不需要在每个层级组件上使用useCallback来增加额外的心智负担.任何组件都只会在你需要的时候被精确更新!

调度

reactivity不会干扰任何的schedule过程,也不会涉及到任何内部优先级的计算(统一为forceUpdate优先级)。

实际上,框架的实现并不是表面上的mutable,所以调度涉及到的多次更新不会影响到框架的运行,无需担心调度被框架干扰。

调试工具

reactivity提供了History进行时光回溯,并且提供标准的chrome插件,但目前暂未开源.