@aha-app/react-easy-state

中文文档
0.0.15-development-nico发布于 2026/02/19MITTypeScriptESM + CJS近 30 天下载 7636

以最小的API反应状态管理. 由ES6代理公司制造.

中文使用文档
文档目录21 节
  1. 反应 Easy 状态 - by 升起图
  2. 导 言:波:
  3. 安装: cd:
  4. 每天使用:太阳镜:
  5. 创建全球商店
  6. 创建被动视图
  7. 创建本地仓库
  8. 高级使用: nerd face :
  9. 添加副作用
  10. API 摘要:书:
  11. 存储( obj)
  12. 视图( CAP)
  13. 批次(fn)
  14. 自动效果( fn)
  15. 明显效果( fn)
  16. 有活演示的例子 : tv:
  17. 文章:发音:
  18. 性能:火箭:
  19. 平台支持: 计算机:
  20. 替代结构:扳手:
  21. 贡献者: sparkles :

反应 Easy 状态 - by 升起图

Build dependencies Status Coverage Status Package size Version License All Contributors

Browser support

新闻: v6.3.0 修补了可以制成的下流错误 僵尸儿童请更新这个版本,至少可以省去一些头痛。 谢谢!

目录

导 言:波:

React Easy State是一个实用的州管理图书馆,有两个功能和两个配套规则.

  1. 总是用 view()。 。 。 .
  2. 总是用 store()。 。 。 .
import React from 'react';
import { store, view } from '@risingstack/react-easy-state';

const counter = store({
  num: 0,
  increment: () => counter.num++
});

export default view(() => (
  <button onClick={counter.increment}>{counter.num}</button>
));

这足以让它在需要时自动更新您的观点. 无论你如何构建或改变你的国营商店 任何在战术上有效的代码.

检查这个 TodoMVC 代码和框 或者说 原始代码 一个更令人兴奋的例子是嵌入式数据、阵列和getter属性.

安装: cd:

npm install @risingstack/react-easy-state

建立一个快速项目

简单状态支持 创建反应应用 没有额外的配置。 只需运行以下命令即可启动.

npx create-react-app my-app
cd my-app
npm install @risingstack/react-easy-state
npm start

您需要npm 5.2+来使用npx.

每天使用:太阳镜:

创建全球商店

store 从通过的对象创建状态存储并返回它。 州立商店的行为就像通过的对象一样. (确切地说,它是原始对象的透明反应代用. )

import { store } from '@risingstack/react-easy-state';

const user = store({ name: 'Rick' });
// stores behave like normal JS objects
user.name = 'Bob';
国营商店可能具有任意的结构,并且可能以任何战术上有效的方式进行变异.

import { store } from '@risingstack/react-easy-state';

// stores can include any valid JS structure
// including nested data, arrays, Maps, Sets, getters, setters, inheritance, ...
const user = store({
  profile: {
    firstName: 'Bob',
    lastName: 'Smith',
    get name() {
      return `${user.profile.firstName} ${user.profile.lastName}`;
    },
  },
  hobbies: ['programming', 'sports'],
  friends: new Map(),
});

// stores may be mutated in any syntactically valid way
user.profile.firstName = 'Bob';
delete user.profile.lastName;
user.hobbies.push('reading');
user.friends.set('id', otherUser);

Async操作可以用标准Async/await语法来表示.

import { store } from '@risingstack/react-easy-state';

const userStore = store({
  user: {},
  async fetchUser() {
    userStore.user = await fetch('/user');
  },
});

export default userStore;

国营商店可以进口和使用其他国营商店.

用户Store.js

import { store } from '@risingstack/react-easy-state';

const userStore = store({
  user: {},
  async fetchUser() {
    userStore.user = await fetch('/user');
  },
});

export default userStore;

食谱Store.js

import { store } from '@risingstack/react-easy-state';
import userStore from './userStore';

const recipesStore = store({
  recipes: [],
  async fetchRecipes() {
    recipesStore.recipes = await fetch(
      `/recipes?user=${userStore.user.id}`,
    );
  },
});

export default recipesStore;

包装您的国家仓库 store 尽快.

// DON'T DO THIS
const person = { name: 'Bob' };
person.name = 'Ann';

export default store(person);
// DO THIS INSTEAD
const person = store({ name: 'Bob' });
person.name = 'Ann';

export default person;

第一个例子不会引发重犯 person.name = 'Ann' 变异,因为它针对的是生物体. 变换生- 无 store- 包装的物体 - 不会安排好的.

避免使用 this 国家商店方法的关键词.

import { store, view } from '@risingstack/react-easy-state';

const counter = store({
  num: 0,
  increment() {
    // DON'T DO THIS
    this.num++;
    // DO THIS INSTEAD
    counter.num++;
  },
});

export default view(() => (
  <div onClick={counter.increment}>{counter.num}</div>
));

this.num++ 没用的,因为 increment 被传递作为回电 失去它 this。您应当使用直接对象引用 - counter - 而不是说 this。 。 。 .

创建被动视图

以 view 把它们变成被动的观点。 反应视图每一次重现一个存储器 - 在其渲染中使用 - 变化.

import React from 'react';
import { view, store } from '@risingstack/react-easy-state';

// this is a global state store
const user = store({ name: 'Bob' });

// this is re-rendered whenever user.name changes
export default view(() => (
  <div>
    <input
      value={user.name}
      onChange={ev => (user.name = ev.target.value)}
    />
    <div>Hello {user.name}!</div>
  </div>
));
用 view - 包括类和功能的 - 即使他们似乎不直接使用商店.

在其渲染过程中使用商店或商店部分部件的每个部件都必须被包裹 view。有时储存的使用并不明确,容易错过.

import { view, store } from '@risingstack/react-easy-state';

const appStore = store({
  user: { name: 'Ann' },
});

const App = view(() => (
  <div>
    <h1>My App</h1>
    <Profile user={appStore.user} />
  </div>
));

// DO THIS
const Profile = view(({ user }) => <p>Name: {user.name}</p>);

// DON'T DO THIS
// This won't re-render on appStore.user.name = 'newName' like mutations
const Profile = ({ user }) => <p>Name: {user.name}</p>;

如果你是的话 百分百确认 您的组件没有使用任何您可以跳过的任何存储 view 包装.

import React from 'react';

// you don't have to wrap this component with `view`
export default (() => <p>This is just plain text</p>);

view 不过,即使在这种情况下,也建议进行包装.

  • 它能让你免于未来的头痛 随着项目的发展 你开始使用这些组件中的商店.
  • view 几乎相当于 memo 如果你不使用任何商店。 这几乎总是很好的有.

单一活性成分可能在其渲染内使用多个储存.

import React from 'react';
import { view, store } from '@risingstack/react-easy-state';

const user = store({ name: 'Bob' });
const timeline = store({ posts: ['react-easy-state'] });

// this is re-rendered whenever user.name or timeline.posts[0] changes
export default view(() => (
  <div>
    <div>Hello {user.name}!</div>
    <div>Your first post is: {timeline.posts[0]}</div>
  </div>
));

view 执行最佳 shouldComponentUpdate (或 memo用于您的组件.

  • 使用 PureComponent 或者说 memo 将不提供额外的业绩效益.

  • 定义自定义 shouldComponentUpdate 当您在它内部应用一些特定的用法时,可能很少提供性能效益.

反应成份进行分批处理。 多个同步存储突变不会导致同一组件的多次重接.

import React from 'react';
import { view, store } from '@risingstack/react-easy-state';

const user = store({ name: 'Bob', age: 30 });

function mutateUser() {
  user.name = 'Ann';
  user.age = 32;
}

// calling `mutateUser` will only trigger a single re-render of the below component
// even though it mutates the store two times in quick succession
export default view(() => (
  <div onClick={mutateUser}>
    name: {user.name}, age: {user.age}
  </div>
));

如果您将您的商店同步进行多次突变 异地任务来源, 多个调值可能很少发生。 如果遇到性能问题,您可以使用 batch 函数. batch(fn) 立即执行已传递的函数,并批次任何后续的重递,直到函数执行完成.

import React from 'react';
import { view, store, batch } from '@risingstack/react-easy-state';

const user = store({ name: 'Bob', age: 30 });

function mutateUser() {
  // this makes sure the state changes will cause maximum one re-render,
  // no matter where this function is getting invoked from
  batch(() => {
    user.name = 'Ann';
    user.age = 32;
  });
}

export default view(() => (
  <div>
    name: {user.name}, age: {user.age}
  </div>
));

注: 反应小组计划在未来改进成品分批处理。 这个 batch 函数和内置分批方式在未来可能会被贬值和去除,有利于React自己的分批方式.

总是应用 view 当您将它与其他更高顺序组件结合时,它成为最新的(最内在的)包装器.

import { view } from '@risingstack/react-easy-state';
import { withRouter } from 'react-router-dom';
import { withTheme } from 'styled-components';

const Comp = () => <div>A reactive component</div>;

// DO THIS
withRouter(view(Comp));
withTheme(view(Comp));

// DON'T DO THIS
view(withRouter(Comp));
view(withTheme(Comp));

用(前 v4. 4) 反应路由器 .

  • 如果路由没有适当更新,请将您 view(Comp) - 带着 Route内部 - 内 withRouter(view(Comp))。让反应路由器知道何时更新.

  • HOCs的顺序,总是使用 withRouter(view(Comp))。 。 。 .

如果您使用 React 路由器 4.4+ ,则无需此操作 。 你可以找到更多细节 和一些关于这一点的推理 此反应路由文件页面。 。 。 .

使用 React 开发工具 .

如果您想让 React 开发者工具识别您的被动视图组件名称, 您必须通过任意一个 命名函数 或匿名函数 名称推论 页:1 view 包装.

import React from 'react';
import { view, store } from '@risingstack/react-easy-state';

const user = store({
  name: 'Rick',
});

const componentName = () => (
  <div>{user.name}</div>
);

export default view(componentName);

将巢数据传递给第三方组件.

第三方帮助者,如数据网,可能由许多内部组件组成,这些组件不能由 view,但有时你希望 当通过的数据变异时,他们会重新回复。 传统回放组件在道具因参考而改变时会再发回回回放,因此变换所传回的回放数据在这种情况下不会起作用. 您可以在将可观测数据复制到组件之前,通过深层克隆解决这个问题。 这为每个商店变异的消耗成分创造了新的参考.

import React from 'react';
import { view, store } from '@risingstack/react-easy-state';
import Table from 'rc-table';
import cloneDeep from 'lodash/cloneDeep';

const dataStore = store({
  items: [
    {
      product: 'Car',
      value: 12,
    },
  ],
});

export default view(() => (
  <Table data={cloneDeep(dataStore.items)} />
));

创建本地仓库

单通全球商店对于像当前用户一样的东西来说是完美的,但有时拥有本地组件状态会更好. 只要在函数组件内创建一个存储,或者在这些情况中作为类组件属性.

函数组件中的本地存储

import React from 'react'
import { view, store } from '@risingstack/react-easy-state'

export default view(() => {
  const counter = store({ num: 0 })
  const increment = () => counter.num++
  return <button={increment}>{counter.num}</button>
})

本地商店在功能上依赖于React钩. 它们要求回放和回放DOM v16.8+或回放原生活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活.

您可以使用反应钩 - 包括 useState - 在功能组件,Easy State 不会干扰它们。 考虑使用 自动效果 代替 useEffect 钩上最好的体验,虽然.

import React from 'react';
import { view, store } from '@risingstack/react-easy-state';

export default view(() => {
  const [name, setName] = useState('Ann');
  const user = store({ age: 30 });
  return (
    <div>
      <input value={name} onChange={ev => setName(ev.target.value)} />
      <input
        value={user.age}
        onChange={ev => (user.age = ev.target.value)}
      />
    </div>
  );
});

类组件的本地储存

import React, { Component } from 'react';
import { view, store } from '@risingstack/react-easy-state';

class Counter extends Component {
  counter = store({ num: 0 });
  increment = () => counter.num++;

  render() {
    return (
      <button onClick={this.increment}>{this.counter.num}</button>
    );
  }
}

export default view(Counter);
你也可以用香草来 setState 在你的班组,Easy State 不会干扰它.

import React, { Component } from 'react';
import { view, store } from '@risingstack/react-easy-state';

class Profile extends Component {
  state = { name: 'Ann' };
  user = store({ age: 30 });

  setName = ev => this.setState({ name: ev.target.value });
  setAge = ev => (this.user.age = ev.target.value);

  render() {
    return (
      <div>
        <input value={this.state.name} onChange={this.setName} />
        <input value={this.user.age} onChange={this.setAge} />
      </div>
    );
  }
}

export default view(Profile);

不要把本地商店命名为 state它可能与防止国家直接变异的穿插规则相冲突.

import React, { Component } from 'react';
import { view, store } from '@risingstack/react-easy-state';

class Profile extends Component {
  // DON'T DO THIS
  state = store({});
  // DO THIS
  user = store({});
  render() {}
}

从道具中衍生出本地商店(getDerivedStateFromProps) (中文(简体) ).

包含的类组件 view 拥有额外的静态 deriveStoresFromProps 与香草类似的生命周期方法 getDerivedStateFromProps。 。 。 .

import React, { Component } from 'react';
import { view, store } from '@risingstack/react-easy-state';

class NameCard extends Component {
  userStore = store({ name: 'Bob' });

  static deriveStoresFromProps(props, userStore) {
    userStore.name = props.name || userStore.name;
  }

  render() {
    return <div>{this.userStore.name}</div>;
  }
}

export default view(NameCard);

您不应返回一个对象, 而是应当直接改变接收的商店 。 如果您在单个组件上有多个本地商店, 它们都会在第一个道具参数之后作为参数—— 按定义顺序—— 传递 .

高级使用: nerd face :

添加副作用

使用 autoEffect 以自动副作用响应您的存储更改。 自动效果应当包含链末端逻辑——比如将文档标题更改或将数据保存到localStorage. view 是一种特殊的自动效果,可以渲染.

永远不要使用自动效果从其他数据中获取数据. 使用动态获取器代替 .

import { store, autoEffect } from '@risingstack/react-easy-state';

// DON'T DO THIS
const store1 = store({ name: 'Store 1' })
const store2 = store({ name: 'Store 2' })
autoEffect(() => store2.name = store1.name)

// DO THIS INSTEAD
const store1 = store({ name: 'Store 1' })
const store2 = store({ get name () { return store1.name } })

全球自动效果

全球自动效应可创建于 autoEffect 并清理出来 clearEffect。 。 。 .

import { store, autoEffect, clearEffect } from '@risingstack/react-easy-state';

const app = store({ name: 'My App' })
const effect = autoEffect(() => document.title = app.name)

// this also updates the document title
app.name = 'My Awesome App'

clearEffect(effect)
// this won't update the document title, the effect is cleared
app.name = 'My App'

函数组件中的本地自动效果

在函数组件中使用本地自动效果而不是 useEffect 当它们内部使用活性储存时会用到钩子. 当组件卸载时,这些局部效应会自动清除.

import React from 'react'
import { store, view, autoEffect } from '@risingstack/react-easy-state';

export default view(() => {
  const app = store({ name: 'My App' })
  // no need to clear the effect
  autoEffect(() => document.title = app.name)
})
明确没有像香草道具和状态这样的被动依赖性通过函数组件中的本地自动效应.

由于React hooks的设计,你必须明确将所有无反应数据传递给钩状依赖阵列. 这使得当无反应数据发生变化时,效果也能运行.

import React from 'react'
import { store, view, autoEffect } from '@risingstack/react-easy-state';

export default view(({ greeting }) => {
  const app = store({ name: 'My App' })
  // pass `greeting` in the dependency array because it is not coming from a store
  autoEffect(() => document.title = `${greeting} ${app.name}`, [greeting])
})

类组件中的本地自动效果

当组件卸载时,必须清除类组件中的局部效应.

import React, { Component } from 'react'
import { store, view, autoEffect } from '@risingstack/react-easy-state';

class App extends Component {
  app = store({ name: 'My App' })

  componentDidMount () {
    this.effect = autoEffect(() => document.title = this.app.name)
  }

  componentWillUnmount () {
    // local effects in class components must be cleared on unmount
    clearEffect(this.effect)
  }
}

API 摘要:书:

存储( obj)

从通过的对象创建可观察到的存储并返回。 可用于外部组件 全球库存 和内部组件 本地仓库。 。 。 .

import { store } from '@risingstack/react-easy-state';

const user = store({ name: 'Rick' });

视图( CAP)

创建一个 被动视图 从经过的组件返回。 反应视图在它内部使用的任何存储数据被变异时都会重新发送.

import React from 'react';
import { view, store } from '@risingstack/react-easy-state';

const user = store({ name: 'Bob' });

export default view(() => (
  <div>Hello {user.name}!</div>
));

批次(fn)

立即执行已传递的函数,并批量其内的所有存储突变. 断接突变保证不会引发不必要的双重成份。 大多数任务源都是自动批量的,只使用 batch 如果你遇到表现问题.

import React from 'react';
import { view, store } from '@risingstack/react-easy-state';

const user = store({ name: 'Bob' });

function setName() {
  batch(() => {
    user.name = 'Rick'
    user.name = 'Ann'
  })
}

自动效果( fn)

从经过的函数创建反应函数,立即执行,并返回. 一个反应函数在它内部使用的任何存储数据被变异时都会自动重放.

两者皆可用 外部 财务报告和审定财务报表 内部 组件.

import { store, autoEffect } from '@risingstack/react-easy-state';

const user = store({ name: 'Bob' })

autoEffect(() => document.title = user.name)

明显效果( fn)

使用反应函数(返回于 autoEffect)并清除其反应. 清除后的反应功能将不再在相关商店突变上重新运行. 函数组件内创建的活性函数在组件卸载时自动清除.

import { store, autoEffect, clearEffect } from '@risingstack/react-easy-state';

const user = store({ name: 'Bob' })

const effect = autoEffect(() => document.title = user.name)
clearEffect(effect)

有活演示的例子 : tv:

初学者

高级

文章:发音:

性能:火箭:

您可以将 Easy State 与 Plain React 等州管理图书馆进行比较,其基准如下: 它的性能比"MobX"好一点,和"Redux"类似.

平台支持: 计算机:

  • 节点:6及以上
  • 铬:49及以上
  • 火狐:38及以上
  • 萨法里:10及以上
  • 边缘:12及以上
  • 歌剧院:36及以上
  • 土著反应: 0.59和以上

这个库基于不可多填的ES6代理. 由于这个原因,它永远不会支持IE.

替代结构:扳手:

此库检测是否使用ES6或普通JS模块,并为您提供正确的格式. 默认捆绑使用ES6特性,这些特性可能尚未被一些变更工具所支持. 如果在构建过程中遇到问题,可以从下面切换到ES5构建中的一种.

  • @risingstack/react-easy-state/dist/es.es6.js 曝光一个带有ES6模块的ES6架构.
  • @risingstack/react-easy-state/dist/es.es5.js 暴露一个ES5的建筑,并配有ES6模块.
  • @risingstack/react-easy-state/dist/cjs.es6.js 曝光一个带有通用JS模块的ES6构建.
  • @risingstack/react-easy-state/dist/cjs.es5.js 曝光一个ES5架构并有通用JS模块.

如果使用捆绑器,则设置一个别名 @risingstack/react-easy-state 指向你们想要的建筑 你可以学会如何用网络包装 这里 并随卷而出 这里。 。 。 .

贡献者: sparkles :

总是欢迎捐款,请读我们 提供文档。 。 。 .

感谢这些伟大的人emoji 密钥:


米克洛斯·贝尔塔兰

💻 ⚠️ 📖 📝

罗兰

💻 ⚠️ 📖

丹尼尔·格吉利

💻 🎨 💡

彼得·齐比克

🚇

本项目遵循 全部贡献者 规格。 任何捐款都欢迎!

版本与发布记录

@aha-app/react-easy-state 共发布 17 个版本,首次发布于 2020/04/13;过去 12 个月发布了 1 个版本。

版本发布日期距今
0.0.15-development-nicolatest2026/02/198 个月前
0.0.14-development2023/01/053 年前
0.0.13-development2022/04/094 年前
0.0.12-development2022/04/074 年前
0.0.11-development2022/04/064 年前
0.0.10-development2021/01/205 年前

关于 @aha-app/react-easy-state 的常见问题

@aha-app/react-easy-state 是什么?

以最小的API反应状态管理. 由ES6代理公司制造.

如何安装 @aha-app/react-easy-state?

在项目目录运行 npm install @aha-app/react-easy-state,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:react(*)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@aha-app/react-easy-state 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@aha-app/react-easy-state 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@aha-app/react-easy-state 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=6.0.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@aha-app/react-easy-state 可以商用吗?

@aha-app/react-easy-state 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@aha-app/react-easy-state 的下载量有多少?

根据 npm 官方下载统计,@aha-app/react-easy-state 在 2026/10/05 – 2026/11/03 这 30 天内被下载 7,636 次,日均约 255 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@aha-app/react-easy-state 还在维护吗?

最新版本 0.0.15-development-nico 发布于 2026/02/19(8 个月前);至今共发布 17 个版本,其中过去 12 个月发布了 1 个;首次发布于 2020/04/13。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。