@eficy/reactive-react
Version:
React bindings for @eficy/reactive - MobX-compatible reactive state management with React integration
279 lines (205 loc) • 5.77 kB
Markdown
# @eficy/reactive-react
React bindings for @eficy/reactive - MobX-compatible reactive state management with React integration.
## 🚀 Quick Start
### Installation
```bash
npm install @eficy/reactive-react
# or
yarn add @eficy/reactive-react
# or
pnpm add @eficy/reactive-react
```
### Basic Usage
```tsx
import React from 'react';
import { observable, action, observer } from '@eficy/reactive-react';
// 使用 observable 创建响应式状态 (MobX 兼容语法)
const store = observable({
count: 0,
name: 'Hello'
});
// 创建 actions
const increment = action(() => {
store.set('count', store.get('count') + 1);
});
const updateName = action((newName: string) => {
store.set('name', newName);
});
// 使用 observer 让组件响应式
const Counter = observer(() => (
<div>
<h1>{store.get('name')}: {store.get('count')}</h1>
<button onClick={increment}>+1</button>
<button onClick={() => updateName('Updated!')}>Update Name</button>
</div>
));
export default Counter;
```
## 📚 Core API
### observable
主要的入口点,类似 MobX 的 `observable` 方法:
```tsx
import { observable } from '@eficy/reactive-react';
// 自动检测类型并创建对应的可观察对象
const store = observable({
count: 0,
items: ['a', 'b', 'c']
});
const arr = observable([1, 2, 3]);
const map = observable(new Map());
const set = observable(new Set());
const primitive = observable(42);
```
### 显式方法
```tsx
// 创建可观察对象
const store = observable.object({ count: 0 });
// 创建可观察数组
const items = observable.array(['apple', 'banana']);
// 创建可观察的基本类型 (Box)
const count = observable.box(0);
// 创建可观察 Map
const userMap = observable.map();
// 创建可观察 Set
const tagSet = observable.set();
```
### observer
将 React 组件转换为响应式组件:
```tsx
import { observer } from '@eficy/reactive-react';
const MyComponent = observer(() => {
return <div>Count: {store.get('count')}</div>;
});
// 带 forwardRef 的用法
const MyInput = observer(React.forwardRef((props, ref) => {
return <input ref={ref} value={store.get('value')} />;
}), { forwardRef: true });
```
### useObserver Hook
在函数组件中直接使用响应式逻辑:
```tsx
import { useObserver } from '@eficy/reactive-react';
function MyComponent() {
return useObserver(() => (
<div>Count: {store.get('count')}</div>
));
}
```
### action
批处理状态更新,确保只触发一次重新渲染:
```tsx
import { action } from '@eficy/reactive-react';
const updateMultiple = action(() => {
store.set('count', 10);
store.set('name', 'Updated');
// 只会触发一次重新渲染
});
```
## 🎯 高级用法
### 计算值
```tsx
import { computed } from '@eficy/reactive-react';
const store = observable({
firstName: 'John',
lastName: 'Doe'
});
const fullName = computed(() =>
`${store.get('firstName')} ${store.get('lastName')}`
);
const MyComponent = observer(() => (
<div>Full name: {fullName()}</div>
));
```
### 数组操作
```tsx
const items = observable(['apple', 'banana']);
const ItemList = observer(() => (
<ul>
{items.toArray().map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
));
// 添加项目
const addItem = action(() => {
items.push('orange');
});
```
### Map 和 Set
```tsx
const userMap = observable.map<string, User>();
const tagSet = observable.set<string>();
const UserList = observer(() => {
// 确保通过访问 size 建立依赖关系
const mapSize = userMap.size;
const users = Array.from(userMap.entries());
return (
<div>
<h3>Users ({mapSize}):</h3>
{users.map(([id, user]) => (
<div key={id}>{user.name}</div>
))}
</div>
);
});
```
## 🔄 从 MobX 迁移
@eficy/reactive-react 提供了与 MobX 兼容的 API,迁移通常很简单:
```tsx
// MobX
import { observable, action, computed } from 'mobx';
import { observer } from 'mobx-react';
// @eficy/reactive-react
import { observable, action, computed, observer } from '@eficy/reactive-react';
// API 基本相同!
const store = observable({
count: 0
});
const increment = action(() => {
store.set('count', store.get('count') + 1);
});
```
## ⚡ 性能特性
- **精细化更新**: 只有依赖变化的组件会重新渲染
- **自动批处理**: `action` 内的多个更新会被批处理
- **高效依赖追踪**: 基于 `@preact/signals-core` 的高性能实现
- **懒计算**: 计算值只在被访问时计算
## 🧪 测试
```tsx
import { render, screen, fireEvent } from '@testing-library/react';
import { observable, action, observer } from '@eficy/reactive-react';
it('should update component when observable changes', () => {
const store = observable({ count: 0 });
const increment = action(() => store.set('count', store.get('count') + 1));
const Counter = observer(() => (
<div>
<span data-testid="count">{store.get('count')}</span>
<button data-testid="increment" onClick={increment}>+</button>
</div>
));
render(<Counter />);
expect(screen.getByTestId('count')).toHaveTextContent('0');
fireEvent.click(screen.getByTestId('increment'));
expect(screen.getByTestId('count')).toHaveTextContent('1');
});
```
## 📝 TypeScript
完全支持 TypeScript,提供类型安全的 API:
```tsx
interface UserStore {
name: string;
age: number;
}
const userStore = observable<UserStore>({
name: 'John',
age: 25
});
// 类型安全的访问
const name: string = userStore.get('name');
const age: number = userStore.get('age');
```
## 📖 更多信息
- [GitHub Repository](https://github.com/yee94/eficy)
- [@eficy/reactive 文档](../reactive/README.md)
## 📄 License
MIT