什么是 Reactive?

⚛️ Reactive 是一个为 JavaScript 应用提供状态管理功能的库,直观、灵活、使用 TypeScript 编写。

  • 😊 上手友好:通过 create 方法覆盖超过 80% 的使用场景。
  • 🧩 使用灵活:想要改变存储状态?随时随地通过 mutate 修改就好。
  • ⚡️ 性能优化:利用 Proxy API 尽可能提供最佳性能。
  • 🏄 框架无关:在 React 和 Vanilla JavaScript 中都能良好工作。
  • 🦄 TypeScript 支持:用 TypeScript 编写,完全类型化,更好的开发体验。
  • 🛠️ DevTools 集成:开箱即用的 Redux DevTools 兼容性。

React 使用示例

这里是一个在 React 应用程序中使用 Reactive 的简单示例。

import { create } from '@shined/reactive'

const store = create({ count: 1 })
const addOne = () => store.mutate.count++

function App() {
  const count = store.useSnapshot((s) => s.count)

  return (
    <div>
      <p>计数为 {count}</p>
      <button onClick={addOne}>增加</button>
    </div>
  )
}

更多信息,请参阅 React 用法API 参考

在线尝试

你可以在 CodeSandbox 上在线尝试 Reactive。

自由变更,安全消费

Reactive 采用了读写分离的策略,通过 store.mutate 对象提供了一种更加直观的变更状态的方式。当需要改变状态时,直接修改 store.mutate 对象即可!

export const store = create({
  count: 1,
  user: { name: 'Bob' }
})

export function increment() {
  store.mutate.count++
}

export function updateUser() {
  store.mutate.user = { name: 'Alice' }
}

对于消费,它通过 React 部分的 store.useSnapshot 和纯 JavaScript 部分的 store.snapshot 提供了一个访问状态的简单方法,以确保安全。这种方法生成的非扩展快照状态防止了意外修改。

// 在 React 组件中
const { count } = store.useSnapshot()
const count = store.useSnapshot((s) => s.count)

// 在 Vanilla JavaScript/TypeScript 中
const { count } = store.snapshot()
const count = store.snapshot(s => s.count)

可选的渲染优化

此外,Reactive 还提供了一个可选的渲染优化功能。

// 只有当 `count` 改变时才重新渲染,`s => s.count` 为 selector,即选择器,用于选取指定状态
const count = store.useSnapshot((s) => s.count)

你可以使用 selector 来指定你想要选取的状态,这将只在指定的状态改变时才重新渲染。如果不指定,默认情况下,使用了完整快照的组件会在状态的任何部分发生改变时,触发组件的重新渲染。

提示

关于 selector API 的设计,以及为什么放弃「自动依赖收集」的方案,可参考 proxy-compareissue#65

关于 selector 的一个更全的示例:

import { create } from '@shined/reactive'

const store = create({
  name: 'Bob',
  age: 18,
  hobbies: ['游泳', '跑步'],
  address: { city: { name: '纽约' } },
})

export default function App() {
  // 当 store 的任何部分改变时,将触发重新渲染
  const state = store.useSnapshot()

  // 只有当 store 中的 `city` 对象改变时才重新渲染
  const { name: cityName } = store.useSnapshot((s) => s.address.city)

  // 只有当 store 中的 `hobbies` 对象和 `age` 属性改变时才重新渲染
  const [hobbies, age] = store.useSnapshot((s) => [s.hobbies, s.age] as const)

  // 只有当 store 中的 `name` 改变时才重新渲染
  const name = store.useSnapshot((s) => s.name)
}