É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
, , . .
, .
, , , .
.