إدارة الدولة الموجهة للخدمة مع مصباح luwak

نظرًا لحقيقة أن 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
# 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.


:


صورة هندسة الخدمة



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