React中的另一種狀態管理方案Valtio

千鋒IT教育發表於2023-03-15

React中的狀態管理是開發人員需要解決的問題。 總有一些新庫給你選擇,而選擇合適的庫可能是一項困難的工作

狀態管理一直是React中開發人員需要解決的問題,如何有條理的組織資料,如何快速的在專案中整合,這些都是我們做專案時選擇技術的標準。

Redux一直是我們react專案中不二的狀態管理外掛,但是redux的配置以及各種外掛的安裝一直是很多人員頭疼的一個問題,太麻煩了。但是隨著ReduxToolkit的出現,確實解決了這個問題,直接安裝,就不再需要繼續安裝各類其他外掛,直接上手就能用,簡單方便。但是很多時候,我們的專案可能根本不需要這麼笨重的外掛,雖然redux很好,但是畢竟這麼多年過去了,一代新人換舊人。前端這個大坑中,總會出現新的技術、框架來埋葬那些老傢伙。

代理

Proxy物件用於建立一個物件的代理,從而實現基本操作的攔截和自定義(如屬性查詢、賦值、列舉、函式呼叫等)。

自ES6版本以來,我們在JavaScript中有代理。 代理接收兩個引數:

  • target - 要代理的原始物件
  • handler - 定義物件的操作

這是我們如何使用JavaScript建立代理的方式:

const handler = {
  get: function (obj, prop) {
    return prop in obj ? obj[prop] : 37;
  },
};
const p = new Proxy({}, handler);
p.a = 1;
p.b = undefined;
console.log(p.a, p.b); // 1, undefined
console.log('c' in p, p.c); // false, 37

Valtio

Valtio是一個用於對React和JavaScript應用程式簡單的代理狀態的庫。它使用了js中Proxy這個語法,能讓我們可以非常方便的在react中整合狀態管理功能。

npm init vite@latest # 建立react專案npm i valtio # 進入專案,安裝依賴

我們需要做的是包裝我們的狀態物件,然後我們可以在我們的應用程式中的任何地方進行改變:

import { proxy } from 'valtio';type IStore = {
  count: number;
  list: Item[];};// 定義資料,使用proxy進行包括修飾const store = proxy<IStore>({
  count: 1,
  list: [],});/** * 改變資料 * @param step */export const countPlus = (step: number) => {
  store.count += step;};/** * 新增資料到列表 * @param txt */export const addToList = (txt: string) => {
  store.list.push({
    id: Date.now(),
    txt,
  });};export default store;

定義好的資料直接在元件中進行引入就能使用,useSnapshot可以獲取我們定義好的狀態資料,使用之後在元件中就是一個響應式的效果,只要資料改變了元件就會直接進行更新

import { useSnapshot } from 'valtio';import store, { countPlus } from '../store';function Counter() {
  const { count } = useSnapshot(store);
  return (
    <div>
      <h1>計數器--{count}</h1>
      <button
        onClick={() => {
          countPlus(2);
        }}
      >
        改變
      </button>
    </div>
  );}export default Counter;

valtio簡單直接,充分使用了proxy這個物件,簡單粗暴的實現react專案的狀態管理。在一些小型專案中是一個不錯的選擇。當然當然大家還是需要在專案中努力做好自己程式碼結構的組織方便後去資料的維護。

├── index.html├── package-lock.json├── package.json├── public│   └── vite.svg├── readme.md├── src│   ├── @types│   │   └── app.d.ts│   ├── App.css│   ├── App.tsx│   ├── assets│   │   └── react.svg│   ├── components│   │   ├── Counter.tsx│   │   ├── List│   │   │   ├── index.tsx│   │   │   └── list-input.tsx│   │   ├── Movies.tsx│   │   └── ShowCounter.tsx│   ├── index.css│   ├── main.tsx│   ├── store│   │   ├── features│   │   │   └── movie.ts│   │   └── index.ts│   └── vite-env.d.ts├── tsconfig.json├── tsconfig.node.json└── vite.config.ts


store,目錄儲存valtio的資料。index.ts做為入口,可以引入其他的子節點資料

store/features,目錄可以根據功能做拆分處理。每一個功能對應一個檔案

比如此處我的movie.ts檔案的內容如下

// store/features/movie.tsimport { proxy } from 'valtio';// 進行分割export const movie = proxy({
  movies: [],});export const loadMovieData = async () => {
  const res = await fetch(
    '
  ).then((data) => data.json());
  movie.movies = res.data.list;};

完成的store/index.ts檔案如下

import { proxy } from 'valtio';import { movie } from './features/movie';/** * 定義資料 */const store = proxy<IStore>({
  count: 1,
  list: [],
  movie, // 引入拆分好的檔案});/** * 改變資料 * @param step */export const countPlus = (step: number) => {
  store.count += step;};/** * 新增資料到列表 * @param txt */export const addToList = (txt: string) => {
  store.list.push({
    id: Date.now(),
    txt,
  });};export default store;

而我元件中如果要獲取資料,可以直接拿來用

// components/Movie.tsximport { useEffect } from 'react';import { useSnapshot } from 'valtio';import store from '../store';import { loadMovieData } from '../store/features/movie';function Movies() {
  const { movie } = useSnapshot(store); // useSnapshot取資料  // console.log(movie);  useEffect(() => {
    loadMovieData();
  }, []);
  return (
    <div className='movies'>
      <ul>
        {movie.movies.map((item: any) => (
          <li key={item.albumId}>{item.name}</li>
        ))}
      </ul>
    </div>
  );}export default Movies;


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70023145/viewspace-2939858/,如需轉載,請註明出處,否則將追究法律責任。

相關文章