MobX

Ѐункция makeObservable Π΄Π΅Π»Π°Π΅Ρ‚ класс отслСТиваСмым. Ѐункция makeAutoObservable Π΄Π΅Π»Π°Π΅Ρ‚ класс отслСТиваСмым ΠΏΠΎ ΠΏΠ΅Ρ€Π΅Π΄Π°Π½Π½ΠΎΠΌΡƒ контСксту ΠΈ ΡΠ°ΠΌΠΎΡΡ‚ΠΎΡΡ‚Π΅Π»ΡŒΠ½ΠΎ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚ Π½ΡƒΠΆΠ½Ρ‹Π΅ для Π½Π΅Ρ‘ настройки.

Π›ΡŽΠ±Π°Ρ созданная функция для MobX - это экшСн, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ мСняСт состояниС. Π’ ΠΎΡ‚Π»ΠΈΡ‡ΠΈΠ΅ ΠΎΡ‚ Redux, состояниС Π² Π΄Π°Π½Π½ΠΎΠΌ ΠΌΠ΅Π½Π΅Π΄ΠΆΠ΅Ρ€Π΅ ΠΌΠΎΠΆΠ½ΠΎ ΠΌΡƒΡ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ. Π’ΠΎ Π΅ΡΡ‚ΡŒ, Ссли ΠΌΡ‹ ΠΈΠ·ΠΌΠ΅Π½ΠΈΠΌ ΠΊΠ°ΠΊΠΎΠ΅-Π»ΠΈΠ±ΠΎ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅, Ρ‚ΠΎ MobX это Π·Π°ΠΌΠ΅Ρ‚ΠΈΡ‚ ΠΈ запустит Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π°.

БСйчас Π½Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ класс, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹ΠΏΠΎΠ»Π½ΡΡ‚ΡŒ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½Ρ‹ΠΉ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π» Π½Π° страницС (Π² Π²ΠΈΠ΄Π΅ ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ²). Π’ ΠΊΠΎΠ½Ρ†Π΅ Π½ΡƒΠΆΠ½ΠΎ просто ΡΠΊΡΠΏΠΎΡ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΎΠ΄ΠΈΠ½ инстанс ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° класса.

State / store / counter.ts

import { makeAutoObservable } from 'mobx';
 
class Counter {
   // пСрСмСнная, которая являСтся состояниСм
   count = 0;
 
   constructor() {
      // настраиваСт Ρ€Π°Π±ΠΎΡ‚Ρƒ с mobx
      makeAutoObservable(this);
   }
 
   increment() {
      this.count = this.count + 1;
   }
 
   decrement() {
      this.count = this.count - 1;
   }
}
 
export default new Counter();

Π”Π°Π»Π΅Π΅ Π½Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ ΠΈΠΌΠΏΠΎΡ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ наш классовый ΠΊΠ°ΡƒΠ½Ρ‚Π΅Ρ€ Π² ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ ΠΈ Π²ΡΡ‚Π°Π²ΠΈΡ‚ΡŒ Π΅Π³ΠΎ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ.
Π’Π΅ΠΏΠ΅Ρ€ΡŒ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΊΠ°ΡƒΠ½Ρ‚Π΅Ρ€ с функциями, описанными Π² MobX, Π½ΡƒΠΆΠ½ΠΎ ΠΎΠ±Π΅Ρ€Π½ΡƒΡ‚ΡŒ вСсь ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ Π² Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ observer, которая отслСТиваСт измСнСния состояний Π² ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π΅ ΠΈ ΠΏΠ΅Ρ€Π΅Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ²Π°Π΅Ρ‚ Π΅Π³ΠΎ.

State / State.tsx

import React from 'react';
import { useState } from 'react';
import styles from './State.module.scss';
import { Button } from '@/components';
import counter from './store/counter';
import { observer } from 'mobx-react-lite';
 
export const State = observer((): JSX.Element => {
   return (
      <div className={styles.wrapper}>
         <h2 className={styles.title}>Π‘Ρ‡Ρ‘Ρ‚Ρ‡ΠΈΠΊ:</h2>
         <h1 className={styles.num}>{counter.count}</h1>
         <Button
            buttonType={'gray'}
            className={styles.reduce}
            onClick={() => counter.decrement()}
         >
            Π£ΠΌΠ΅Π½ΡŒΡˆΠΈΡ‚ΡŒ
         </Button>
         <Button
            buttonType={'purple'}
            className={styles.increase}
            onClick={() => counter.increment()}
         >
            Π£Π²Π΅Π»ΠΈΡ‡ΠΈΡ‚ΡŒ
         </Button>
      </div>
   );
});

И Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ наш счётчик Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ ΠΈ быстро отзываСтся Π½Π° всС дСйствия

Π”Π°Π»Π΅Π΅ ΠΏΡ€ΠΈΠ²Π΅Π΄Ρ‘ΠΌ Π΅Ρ‰Ρ‘ ΠΎΠ΄ΠΈΠ½ ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Π³Π΄Π΅ ΠΌΡ‹ сразу Π΄ΠΎΠ±Π°Π²ΠΈΠΌ Π΄Π°Π½Π½Ρ‹Π΅ ΠΈ Ρ€Π΅Π°Π»ΠΈΠ·ΡƒΠ΅ΠΌ список Π΄Π΅Π»

Todo / store / todo.store.ts

import { makeAutoObservable } from 'mobx';
 
interface ITodo {
   id: number;
   title: string;
   completed: boolean;
}
 
class TodoStore {
   todos: ITodo[] = [
      { id: 1, title: 'Π‘Ρ…ΠΎΠ΄ΠΈΡ‚ΡŒ Π² ΠΌΠ°Π³Π°Π·ΠΈΠ½', completed: false },
      { id: 2, title: 'ΠšΡƒΠΏΠΈΡ‚ΡŒ Ρ…Π»Π΅Π±', completed: false },
      { id: 3, title: 'Π‘ΡŠΠ΅ΡΡ‚ΡŒ Ρ…Π»Π΅Π±', completed: false },
   ];
 
   constructor() {
      makeAutoObservable(this);
   }
 
   addTodo(todo: ITodo) {
      this.todos.push(todo);
   }
 
   removeTodo(id: number) {
      this.todos = this.todos.filter(todo => todo.id !== id);
   }
 
   completeTodo(id: number) {
      this.todos = this.todos.map(todo =>
         todo.id === id ? { ...todo, completed: !todo.completed } : todo,
      );
   }
}
 
export default new TodoStore();

БСйчас список Π΄Π΅Π» рСализуСтся ΠΏΠΎΡ‡Ρ‚ΠΈ Ρ‚Π°ΠΊ ΠΆΠ΅, ΠΊΠ°ΠΊ ΠΈ ΠΏΡ€ΠΎΡˆΠ»Ρ‹ΠΉ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ с ΠΊΠ°ΡƒΠ½Ρ‚Π΅Ρ€ΠΎΠΌ. Π’ MobX ΠΎΡ‡Π΅Π½ΡŒ Π²Π°ΠΆΠ½ΠΎ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΊΠ»ΡŽΡ‡ΠΈ элСмСнтов Π±Ρ‹Π»ΠΈ ΡƒΠ½ΠΈΠΊΠ°Π»ΡŒΠ½Ρ‹ΠΌΠΈ, ΠΈ Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΎΠ½ΠΈ Π½Π΅ являлись индСксами массива

TodoList / TodoList.tsx

import React from 'react';
import { observer } from 'mobx-react-lite';
import todo from './store/todo.store';
import styles from './TodoList.module.scss';
import { Button, Input } from '@/components';
 
export const TodoList = observer(() => {
   return (
      <div className={styles.wrapper}>
         {todo.todos.map(t => (
            <div key={t.id} className={styles.todo}>
               <Input
                  type={'checkbox'}
                  checked={t.completed}
                  onChange={() => todo.completeTodo(t.id)}
               />
               <div>{t.title}</div>
               <Button
                  className={styles.button}
                  buttonType={'purple'}
                  onClick={() => todo.removeTodo(t.id)}
               >
                  X
               </Button>
            </div>
         ))}
      </div>
   );
});

И Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ наш список Π΄Π΅Π» удаляСт сСбя ΠΈ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½Π½Ρ‹ΠΌ

Π’Π°ΠΊ ΠΆΠ΅ Π½ΡƒΠΆΠ½ΠΎ ΡΠΊΠ°Π·Π°Ρ‚ΡŒ, Ρ‡Ρ‚ΠΎ Ссли Π½Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ с Π±ΠΎΠ»Π΅Π΅ Π³Π»ΡƒΠ±ΠΎΠΊΠΈΠΌΠΈ уровнями влоТСнности, Ρ‡Ρ‚ΠΎ Π² ΠΌΠΎΠ± Π½ΡƒΠΆΠ½ΠΎ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ ΠΎΠΏΡ†ΠΈΡŽ deep

Π’Π°ΠΊ ΠΆΠ΅ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΡƒΡ‚ΠΎΡ‡Π½ΠΈΡ‚ΡŒ Π²Π½ΡƒΡ‚Ρ€ΠΈ ΠΎΠ²Π΅Ρ€Ρ€Π°ΠΉΠ΄Π° (Π²Ρ‚ΠΎΡ€ΠΎΠΉ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ ΠΌΠΎΠ±Π°):

  • Ρ‡Ρ‚ΠΎ Π΅ΡΡ‚ΡŒ отслСТиваСмый ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ todos: observable,
  • Ρ‡Ρ‚ΠΎ Π΅ΡΡ‚ΡŒ ΡΠΊΡˆΠ΅Π½Ρ‹ addTodo: action
  • И Ρ‡Ρ‚ΠΎ являСтся вычисляСмым Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ΠΌ computed: Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅
constructor() {
   makeAutoObservable(this, { todos: observable, addTodo: action, computed:  });
}

ВычисляСмыС значСния - это значСния, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΌΡ‹ считаСм Π² ΠΌΠ΅Ρ‚ΠΎΠ΄Π΅, ΠΏΠΎΠΌΠ΅Ρ‡Π΅Π½Π½ΠΎΠΌ ΠΊΠ»ΡŽΡ‡Π΅Π²Ρ‹ΠΌ словом get. Π­Ρ‚ΠΎΡ‚ ΠΌΠ΅Ρ‚ΠΎΠ΄ ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ Π΄ΠΎΠ»ΠΆΠ΅Π½ Π²Ρ‹Ρ‡ΠΈΡΠ»ΡΡ‚ΡŒ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ ΠΊΠ°ΠΊΠΈΡ…-Ρ‚ΠΎ вычислСний. ОсновноС прСимущСство Π² Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎ ΠΌΠ΅Ρ‚ΠΎΠ΄ вызываСтся Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Ρ‚ΠΎΠ³Π΄Π°, ΠΊΠΎΠ³Π΄Π° ΠΎΠ΄ΠΈΠ½ ΠΈΠ· Π΅Π³ΠΎ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠ² ΠΈΠ·ΠΌΠ΅Π½ΠΈΠ» своё Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅. Π’Π°ΠΊΠΎΠΉ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·ΠΈΡ€ΡƒΠ΅Ρ‚ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠΉ.

get total() {
   return `Counter = ${this.timer + this.count}`;
}

Π’Π΅ΠΏΠ΅Ρ€ΡŒ Ρ‚ΡƒΡ‚ примСняСм Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ

<h1 className={styles.num}>{counter.total}</h1>

АсинхронныС ΡΠΊΡˆΠ΅Π½Ρ‹. Они ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ΡΡ Ρ€ΠΎΠ²Π½ΠΎ Ρ‚Π°ΠΊ ΠΆΠ΅, ΠΊΠ°ΠΊ ΠΈ ΠΎΡΡ‚Π°Π»ΡŒΠ½Ρ‹Π΅ ΡΠΊΡˆΠ΅Π½Ρ‹. Π’ΡƒΡ‚ прСдставлСн ΠΏΡ€ΠΈΠΌΠ΅Ρ€ получСния списка Π΄Π΅Π» с сСрвСра jsonplaceholder

todo.store.ts

fetchTodos() {
   fetch('https://jsonplaceholder.typicode.com/todos/')
      .then(response => response.json())
      .then(json => {
         this.todos = [...this.todos, ...json];
      });
}

Π’ΡƒΡ‚ ΠΏΡ€ΠΈ Π½Π°ΠΆΠ°Ρ‚ΠΈΠΈ ΠΊΠ½ΠΎΠΏΠΊΠΈ ΠΌΡ‹ ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ Π΄Π°Π½Π½Ρ‹ΠΉ массив

TodoList.tsx

<Button buttonType={'gray'} onClick={() => todo.fetchTodos()}>
   ΠŸΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ список Π΄Π΅Π»
</Button>

И Π²ΠΈΠ΄ΠΈΠΌ ΠΎΠ³Ρ€ΠΎΠΌΠ½Ρ‹ΠΉ список Π΄Π΅Π»