Zustand

НачинаСм с React ΠΈ Zustand

Π”Π°Π²Π°ΠΉΡ‚Π΅ посмотрим, ΠΊΠ°ΠΊ Zustand Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ с React. Π§Ρ‚ΠΎΠ±Ρ‹ ΠΏΡ€ΠΎΠ΄Π΅ΠΌΠΎΠ½ΡΡ‚Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π΅Π³ΠΎ возмоТности, я создам нСбольшоС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Pokemon. Π­Ρ‚ΠΎ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ состоит ΠΈΠ· Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Π°, ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π° списка ΠΈ Ρ„ΠΎΡ€ΠΌΡ‹ Π²Π²ΠΎΠ΄Π°, которая ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Π΅Ρ‚ Π²Π²ΠΎΠ΄ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ.

Π¨Π°Π³ 1. Установка

Установка Zustand Ρ‚Π°ΠΊ ΠΆΠ΅ проста, ΠΊΠ°ΠΊ установка любого ΠΈΠ· ΠΏΠ°ΠΊΠ΅Ρ‚ΠΎΠ² npm. Π”Π°Π²Π°ΠΉΡ‚Π΅ установим Π΅Π³ΠΎ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ npm ΠΈΠ»ΠΈ yarn.

npm install zustand
yarn add zustand

Π¨Π°Π³ 2. Π‘ΠΎΠ·Π΄Π°Ρ‘ΠΌ Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Π΅

Π”Π°Π»Π΅Π΅ Π΄Π°Π²Π°ΠΉΡ‚Π΅ создадим Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Π΅, ΠΊΠ°ΠΊ ΠΈ Π² любой Π΄Ρ€ΡƒΠ³ΠΎΠΉ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ΅ управлСния состояниСм.

import create from "zustand";
const useStore = create((set) => ({
pokemons: [{ id: 1, name: "Bulbasaur" },
 { id: 2, name: "Ivysaur" },
 { id: 3, name: "Venusaur" },
 { id: 4, name: "Charmander" },
 { id: 5, name: "Charmeleon" },
],
addPokemons: (pokemon) =>
set((state) => ({
 pokemons: [
 { name: pokemon.name, id: Math.random() * 100 },
  ...state.pokemons,
 ]})),
removePokemon: (id) =>
 set((state) => ({
   pokemons: state.pokemons.filter((pokemon) => pokemon.id !== id),
 })),
}));
export default useStore;

Π₯Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Π΅ создаСтся с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ create API, ΠΈ ΡΠΊΡˆΠ΅Π½Ρ‹ ΠΌΠΎΠ³ΡƒΡ‚ Π±Ρ‹Ρ‚ΡŒ созданы, ΠΊΠ°ΠΊ ΠΏΠΎΠΊΠ°Π·Π°Π½ΠΎ Π²Ρ‹ΡˆΠ΅. Доступ ΠΊ этому Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Ρƒ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ Ρ‡Π΅Ρ€Π΅Π· ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π±Π΅Π· использования ΠΊΠ°ΠΊΠΎΠ³ΠΎ-Π»ΠΈΠ±ΠΎ ΠΏΡ€ΠΎΠ²Π°ΠΉΠ΄Π΅Ρ€Π° HOC (ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π° Π±ΠΎΠ»Π΅Π΅ высокого порядка), ΠΊΠ°ΠΊ Π² Redux.

Π¨Π°Π³ 3. ΠŸΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ доступ ΠΊ Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Ρƒ

Zustand Π½Π΅ ΠΏΠΎΠ»Π½ΠΎΡΡ‚ΡŒΡŽ привязан ΠΊ React. Π•Π³ΠΎ ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ с Π»ΡŽΠ±Ρ‹ΠΌΠΈ Π΄Ρ€ΡƒΠ³ΠΈΠΌΠΈ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ°ΠΌΠΈ, Ρ‚Π°ΠΊΠΈΠΌΠΈ ΠΊΠ°ΠΊ Vue ΠΈΠ»ΠΈ Angular. Π”Π°Π²Π°ΠΉΡ‚Π΅ посмотрим, ΠΊΠ°ΠΊ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ доступ ΠΊ Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Ρƒ ΠΈΠ· ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π°.

Доступ ΠΊ ΡΠΎΡΡ‚ΠΎΡΠ½ΠΈΡŽ Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Π° ΠΈ ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ Π΄Π°Π½Π½Ρ‹Ρ… Π² Π²ΠΈΠ΄Π΅ списка

import useStore from "../store";
function List() {
 const pokemons = useStore((state) => state.pokemons);
 const removePokemon = useStore((state) => state.removePokemon);
return (
 <div className="row">
  <div className="col-md-4"></div>
  <div className="col-md-4">
  <ul>{pokemons.map((pokemon) => (
     <li key={pokemon.id}>
      <div className="row">
      <div className="col-md-6">{pokemon.name} </div>
      <div className="col-md-6">
        <button className="btn btn-outline-secondary btn-sm"
         onClick={(e) => removePokemon(pokemon.id)}>X
        </button>
       </div>
      </div>
     </li>
    ))}
  </ul>
</div>
 <div className="col-md-4"></div>
</div>);
}
export default List;

ОбновляСм состояния с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Ρ„ΠΎΡ€ΠΌΡ‹

import { useState } from "react";
import useStore from "../store";

function Form() {
  const [name, setName] = useState("");
  const addPokemons = useStore((state) => state.addPokemons);

  const onChange = (e) => {
    setName(e.target.value);
  };

  const addPokemon = () => {
    addPokemons({ name: name });
    clear();
  };

  const clear = () => setName("");

  return (
    <div className="row">
      <div className="col-md-2"></div>
      <div className="col-md-6">
        <input
          type="text"
          className="form-control"
          onChange={onChange}
          value={name}
        ></input>
      </div>
      <div className="col-md-2">
        <button
          className="btn btn-outline-primary"
          onClick={(e) => addPokemon()}
        >
          Add
        </button>
      </div>
      <div className="col-md-2"></div>
    </div>
  );
}

export default Form;

Как Π²ΠΈΠ΄ΠΈΡ‚Π΅, Zustand Π½Π°ΠΌΠ½ΠΎΠ³ΠΎ Ρ‚ΠΎΡ‡Π½Π΅Π΅ ΠΈ ΠΏΡ€ΠΎΡ‰Π΅, Ρ‡Π΅ΠΌ Redux, Recoil ΠΈΠ»ΠΈ Jotai.

Π¨Π°Π³ 4. ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° асинхронных экшСнов

Одним ΠΈΠ· Ρ€Π΅Π°Π»ΡŒΠ½Ρ‹Ρ… ΠΏΡ€ΠΈΠΌΠ΅Π½Π΅Π½ΠΈΠΉ дСйствия Zustand являСтся ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ Π΄Π°Π½Π½Ρ‹Ρ… Ρ‡Π΅Ρ€Π΅Π· REST API. Π­Ρ‚ΠΈ ΡΠΊΡˆΠ΅Π½Ρ‹ ΠΌΡ‹ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π²Ρ‹ΠΏΠΎΠ»Π½ΡΡ‚ΡŒ асинхронно.

import axios from "axios";
const useStore = create(set => ({
  pokemons: [],
  getPokemons: async ()=> {
    const response = await axios.get('')
    set({ pokemons: response.data })
  }
}))

Асинхронный экшСн ΠΌΠΎΠΆΠ½ΠΎ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ async/await Π² JavaScript. Π’ ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½Π½ΠΎΠΌ Π²Ρ‹ΡˆΠ΅ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΡƒΠ²ΠΈΠ΄Π΅Ρ‚ΡŒ, ΠΊΠ°ΠΊ асинхронныС ΡΠΊΡˆΠ΅Π½Ρ‹ Π·Π°ΠΏΡƒΡΠΊΠ°ΡŽΡ‚ΡΡ Ρ‡Π΅Ρ€Π΅Π· axios.

Шаг 5: Middleware для Zustand

Zustand ΠΈΠΌΠ΅Π΅Ρ‚ нСсколько ΡƒΠ½ΠΈΠΊΠ°Π»ΡŒΠ½Ρ‹Ρ… middleware'ΠΎΠ² ΠΈΠ· ΠΊΠΎΡ€ΠΎΠ±ΠΊΠΈ. НаиболСС извСстными middleware'Π°ΠΌΠΈ ΡΠ²Π»ΡΡŽΡ‚ΡΡ dev tools (ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‰ΠΈΠ΅ инструмСнты Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ Redux) ΠΈ Persist, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΌΠΎΠ³ΡƒΡ‚ ΡΠΎΡ…Ρ€Π°Π½ΡΡ‚ΡŒ Π΄Π°Π½Π½Ρ‹Π΅ Π² Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Π΅.

let useStore : (set)=>{
  /* state and actions */
};
useStore = persist(useStore, { name: 'Bulbasaur' })
useStore = devtools(useStore)

export default useStore = create(useStore);

Π‘ Zustand Π²Ρ‹ Ρ‚Π°ΠΊΠΆΠ΅ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ собствСнный middleware ΠΈ ΠΏΠ»Π°Π³ΠΈΠ½.

Π—Π°ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅

Π’ Π·Π°ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅, Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° Zustand β€” ΠΎΠ΄Π½Π° ΠΈΠ· самых Π»Π΅Π³ΠΊΠΈΡ… Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊ управлСния состояниСм. Он Ρ‚Π°ΠΊΠΆΠ΅ обСспСчиваСт Π³ΠΈΠ±ΠΊΠΎΡΡ‚ΡŒ для Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΡ своСй Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅ΠΌΡ‹Ρ… ΠΌΠΎΠ΄ΡƒΠ»Π΅ΠΉ ΠΈ middlerware для ΡƒΠ»ΡƒΡ‡ΡˆΠ΅Π½ΠΈΡ ΠΎΠΏΡ‹Ρ‚Π° Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ.

НапримСр, Zustand позволяСт ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ доступ ΠΊ Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Ρƒ Π²Π½Π΅ React ΠΈ совмСстим с Redux DevTools, Persist ΠΈ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅Ρ‚ React Hooks, TypeScript ΠΈ Ρ‚. Π΄.

Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ, Zustand выглядит ΠΎΡ‚Π»ΠΈΡ‡Π½Ρ‹ΠΌ ΠΊΠ°Π½Π΄ΠΈΠ΄Π°Ρ‚ΠΎΠΌ Π½Π° пост управлСния состояниСм Π² ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΈ. ΠŸΡ€ΠΎΡΡ‚ΠΎΡ‚Π° Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ Ρ‚Π°ΠΊΠΆΠ΅ Π΄Π΅Π»Π°Π΅Ρ‚ Π΅Π΅ Ρ…ΠΎΡ€ΠΎΡˆΠΈΠΌ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ΠΎΠΌ для Π½Π°Ρ‡ΠΈΠ½Π°ΡŽΡ‰ΠΈΡ….

Last updated