Serviceorientiertes Zustandsmanagement mit Lampe-Luwak

Aufgrund der Tatsache, dass React erstaunliche Funktionen für die Arbeit mit der Anzeige bietet, können Sie sich nur auf die Organisation der Anwendungslogik und der Semantik des Codes konzentrieren, der die Arbeit mit Daten beschreibt. Jene. Bei Auswahl einer Statusverwaltungsbibliothek erfolgt die Auswahl des Stils der zukünftigen Codebasis.


In diesem Artikel wird ein Service-Store-basierter Ansatz betrachtet, der über eine Bibliothek implementiert wird lamp-luwak.


Lampe-Luwak-Bild


TL; DR Wer bald mit dem Schreiben von Code beginnen möchte, kann mit dem nächsten Absatz fortfahren.


Die gesamte Logik in Ihrer Anwendung ist in Dienste unterteilt. Jeder Dienst enthält eine einzelne Seite, deren Änderung die Abonnenten benachrichtigt. Der Dienst enthält auch Logikfunktionen, mit denen Sie auf andere Dienste zugreifen und die unveränderliche Seite neu schreiben können. Diese Funktionen können asynchron sein und Nebenwirkungen enthalten.


lamp-luwak , . , React useProvide useSubscribe . , , .


, - . , embedded . .


subscribe. .



, todo- :


  • ;
  • / ;
  • /.


todos create-react-app


npx create-react-app todos --template typescript --use-npm
# or
yarn create react-app todos --template typescript

lamp-luwak todos


npm i --save lamp-luwak
# or
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, -, - .


// Todo.ts
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.


// Todo/Task.ts
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, .


// TodoCounters.ts
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.


:


Service-Architektur-Image



App.tsx, .


List — .


// List.tsx
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 — .


// Task.tsx
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 — .


// Counters.tsx
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.


// Input.tsx
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 , .


// App.tsx
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, , . .



, .



, , , .
.




All Articles