由于React提供了惊人的显示功能,因此您只能专注于组织应用程序逻辑和描述如何使用数据的代码语义。那些。选择状态管理库后,便会选择未来代码库的样式。
在本文中,我们将考虑通过库实现的基于服务存储的方法lamp-luwak
。

TL; DR希望很快开始编写代码的人可以跳至下一段。
您的应用程序内部的所有逻辑都分为服务,每个服务包含一个方面,更改将通知订阅者。该服务还包含逻辑功能,您可以在其中访问其他服务并重写不可变的一面,这些功能可以是异步的并包含副作用。
lamp-luwak
, . , React useProvide
useSubscribe
. , , .
, - . , embedded . .
subscribe
. .
, todo- :
todos create-react-app
npx create-react-app todos --template typescript --use-npm
yarn create react-app todos --template typescript
lamp-luwak
todos
npm i --save lamp-luwak
yarn add lamp-luwak
, React - , - .
— -, , .
-, store
.
class Todos {
store = [ ];
store
. .
class TodoCounters {
todo = provide(Todo);
provide
, , Todo
.
React
const List = () => {
const todo = useProvide(Todo);
};
-. React useProvide
, — - , Todo
. , .
— , , store
provide
useProvide
/ , .
, List Todo
.
services
, React components
.
sr/
components/ // React
Counters.tsx //
Input.tsx //
Task.tsx //
List.tsx //
services/ //
Todo/
Task.ts //
Todo.ts //
TodoCounters.ts //
App.tsx //
2- . :
Todo
— , add
;TodoCounters
— .
Todo
, Task
, .. , , . , , . , Date, Map, Set. ( SSR) , UI. , . , Task
toggle
, .
Task
, , create
, -, - .
import { create } from 'lamp-luwak';
import { Task } from './Todo/Task';
export class Todo {
store = [
create(Task, { id: 1, label: 'Cook the dinner', completed: false }),
create(Task, { id: 2, label: 'Cook the breakfast', completed: true })
]
add(label: string) {
this.store = this.store.concat(
create(Task, { id: Date.now(), label, completed: false })
);
}
}
Todo
. store
Task
, create
. add
, , Task
. id
, Date.now
.
import { subscribe, modify, action } from 'lamp-luwak';
type Store = {
id: number,
label: string,
completed: boolean
}
export const TaskChanged = action();
export class Task {
store: Store;
constructor(store: Store) {
this.store = store;
subscribe(this, TaskChanged);
}
toggle() {
modify(this).completed = !this.store.completed;
}
}
Task
, . : id
, label
completed
. toggle
, , modify
, , .
TaskChanged
, action
.
— , . , — dispatch
lamp-luwak
.
, , TaskChanged
Task
. subscribe
, — , .. , — , . TaskChanged
, .
import { provide, subscribe } from 'lamp-luwak';
import { Todo } from './Todo';
import { TaskChanged } from './Todo/Task';
export class TodoCounters {
todo = provide(Todo);
store = {
active: 0,
completed: 0
}
constructor() {
subscribe(this.todo, this.calculate, this);
subscribe(TaskChanged, this.calculate, this);
this.calculate();
}
calculate() {
const items = this.todo.store;
const completed = items.filter(item => item.store.completed).length;
const active = items.length - completed;
this.store = { completed, active };
}
}
TodoCounters
, . 2- :
Todo
, , .TaskChanged
, - Task
, completed
, .
calculate
.
:

App.tsx
, .
List
— .
import React from 'react';
import { useProvide } from 'lamp-luwak';
import { Todo } from '../services/Todo';
import { Task } from './Task';
export const List = () => {
const todo = useProvide(Todo);
const items = todo.store;
if (items.length === 0) return null;
return (
<ul>
{items.map(item => (
<Task task={item} key={item.store.id} />
))}
</ul>
)
};
Todo
, useProvide
, List
, , , . , .
Task
— .
import React, { FC } from 'react';
import { useSubscribe } from 'lamp-luwak';
import { Task as TaskClass } from '../services/Todo/Task';
export const Task: FC<{ task: TaskClass }> = ({ task }) => {
useSubscribe(task);
const { label, completed } = task.store;
return (
<li>
<input
className="toggle"
type="checkbox"
checked={completed}
onChange={() => task.toggle()}
/>
<span style={{
textDecoration: completed ? 'line-through' : 'none'
}}>
{label}
</span>
</li>
)
};
Task
, , useSubscribe
, . , toggle
.
Counters
— .
import React from 'react';
import { useProvide } from 'lamp-luwak';
import { TodoCounters } from '../services/TodoCounters';
export const Counters = () => {
const { active, completed } = useProvide(TodoCounters).store;
return (
<>
<div>Active: {active}</div>
<div>Completed: {completed}</div>
</>
)
};
, useProvide
. , TodoCounters
.
Input
— .
add
Todo
. , Todo
, React useState
.
import React, { useState } from 'react';
import { useProvide } from 'lamp-luwak';
import { Todo } from '../services/Todo';
export const Input = () => {
const [text, setText] = useState('Cook the lunch');
const todo = useProvide(Todo);
const add = () => {
todo.add(text);
setText('');
};
return (
<>
<input
onChange={(e) => setText(e.target.value)}
value={text}
autoFocus
onKeyDown={(event: any) => {
if (event.keyCode === 13) add();
}}
/>
<button onClick={add}>Add</button>
</>
);
};
App.tsx
, src
, .
import React from 'react';
import { Input } from './components/Input';
import { List } from './components/List';
import { Counters } from './components/Counters';
const App = () => (
<>
<Input />
<List />
<Counters />
</>
);
export default App;
Enjoy! .
lamp-luwak
, , . .
, .
, , , .
.