Étant donné que React offre des capacités incroyables pour travailler avec l'affichage, vous ne pouvez vous concentrer que sur l'organisation de la logique d'application et la sémantique du code qui décrit comment travailler avec les données. Ceux. en choisissant une bibliothèque de gestion d'état, le choix du style de la future base de code a lieu.
Dans cet article, nous considérerons une approche basée sur un magasin de services implémentée via une bibliothèque lamp-luwak.

TL; DR Celui qui veut commencer à écrire du code bientôt peut passer au paragraphe suivant.
Toute la logique à l'intérieur de votre application est divisée en services, chaque service contient un seul côté, dont le changement informe les abonnés. Le service contient également des fonctions logiques, où vous pouvez accéder à d'autres services et réécrire le côté immuable, ces fonctions peuvent être asynchrones et contenir des effets secondaires.
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, , . .
, .
, , , .
.