Workstation Logo
ผลิตภัณฑ์
AI LabsOpenAI AgentsClaude AgentsGrok BotWorkstation CRM (WSL CRM)การตลาดผลิตภัณฑ์ทั้งหมด
โซลูชัน AI
เวิร์กสเตชัน AIAI SME PackagesAI ส่วนตัวคลัสเตอร์ GPUEdge AIแล็บ AI องค์กรAI ตามอุตสาหกรรม
บริการ
Platform ModernisationDigital EngineeringData Foundations & AIAutonomous Operationsที่ปรึกษา AIระบบอัตโนมัติ DevOpsความมั่นคงปลอดภัยไซเบอร์การพัฒนาซอฟต์แวร์การสร้างเอเจนต์การตั้งค่า MLOps
เกี่ยวกับเรา
พาร์ทเนอร์เรื่องราวลูกค้า
บทความ
เอกสาร
WSL ProxyRing PromoterWSL VaultJobshoutSysOps 24/7
บล็อก
ติดต่อเราLogin
Workstation

เวิร์กสเตชัน AI ซอฟต์แวร์มัลติเอเจนต์ AI โครงสร้างพื้นฐาน GPU และโซลูชันเอเจนต์อัจฉริยะสำหรับธุรกิจยุคใหม่

ติดต่อเรา

โซลูชัน AI

เวิร์กสเตชัน AIAI SME PackagesAI ส่วนตัวคลัสเตอร์ GPUEdge AIแล็บ AI องค์กรAI ตามอุตสาหกรรม

ผลิตภัณฑ์

ผลิตภัณฑ์ทั้งหมดWSL CRM และ ERPการตลาดOpenAI AgentsWSL ProxyRing PromoterWSL VaultJobshoutSysOps 24/7

บริษัท

เกี่ยวกับเราทำไมต้อง Workstationพาร์ทเนอร์เรื่องราวลูกค้าราคาติดต่อ

แหล่งข้อมูล

บทความเอกสารประกอบบล็อกค้นหาแผนผังเว็บไซต์
สำนักงานสหราชอาณาจักร
77-79 Marlowes, Hemel Hempstead HP1 1LFเส้นทาง - ออกทางแยกที่ 20 จาก M25 Outer Londonเลขทะเบียนบริษัท: 11641870จ. - ศ.: 9:00 - 18:00 น. GMT
+44 7515 356 146
สำนักงานเบลเยียม
Workstation SRL, Rue Vanderkindere 34, 1180 Uccle, BrusselsBE 0751.518.683จ. - ศ.: 9:00 - 18:00 น. CET
+32 492 45 67 46
สำนักงานอินเดีย
#159 Sector 9, Pocket 1, DDA Flats, 110077 Dwarka, New Delhi
+91 98881 98841

© 2026 Workstation AI สงวนลิขสิทธิ์

ความเป็นส่วนตัวคุกกี้ข้อกำหนดการให้บริการแผนผังเว็บไซต์

Loading blog...

Home / Blog
WebFrontendReact

การจัดการสถานะขั้นสูงใน React: การเลือกเครื่องมือที่เหมาะสมสำหรับงาน

คู่มือเชิงปฏิบัติสำหรับ Redux Toolkit, Zustand, Jotai, TanStack Query และบริบท React พร้อมรูปแบบสถาปัตยกรรมในโลกแห่งความเป็นจริงและเทคนิคด้านประสิทธิภาพ

Balinder Walia27 พฤษภาคม 25687 min read

การจัดการของรัฐถือเป็นหัวใจสำคัญของทุกแอปพลิเคชัน React ที่ไม่สำคัญ ทำให้ถูกต้องและโค้ดเบสของคุณจะปรับขนาดได้อย่างสวยงาม หากทำผิดและคุณจะพบกับฝันร้ายที่เจาะทะลุอุปกรณ์ UI ที่เก่า และส่วนประกอบต่างๆ ที่ถูกลืมเลือนอีกครั้ง ข่าวดีก็คือว่าระบบนิเวศ React ได้เติบโตอย่างรวดเร็ว ตอนนี้คุณมีเมนูเครื่องมือที่สร้างขึ้นตามวัตถุประสงค์มากมาย เช่น Redux Toolkit, Zustand, Jotai, TanStack Query และ Context API ในตัว ซึ่งแต่ละเมนูได้รับการปรับให้เหมาะกับระดับปัญหาเฉพาะ

บทความนี้จะอธิบายวิธีแก้ปัญหาแต่ละอย่างในเชิงลึก อธิบายข้อดีข้อเสียด้วยตัวอย่างที่เป็นรูปธรรม และให้กรอบการตัดสินใจที่คุณสามารถนำไปใช้กับโครงการของคุณได้ทันที

ทำความเข้าใจกับรัฐประเภทต่างๆ

ภูมิทัศน์การจัดการสถานะ Reactต้นไม้ส่วนประกอบแอพหน้า กหน้า ขคอมพ์คอมพ์คอมพ์คอมพ์useState อาศัยอยู่ที่นี่ท้องถิ่นสำหรับแต่ละองค์ประกอบuseState / useReducerขอบเขต: ส่วนประกอบเดียวเมนูแบบเลื่อนลง อินพุต ฟิลด์แบบฟอร์ม การสลับบริบท Reactขอบเขต: ทรีย่อย / ทั่วทั้งแอป (ความถี่ต่ำ)ธีม, สถานที่, ผู้ใช้ที่ตรวจสอบสิทธิ์, แฟล็กคุณลักษณะชุดเครื่องมือ Reduxขอบเขต: ร้านค้าระดับโลกพร้อม DevToolsสถานะที่ซับซ้อน มิดเดิลแวร์ การเดินทางข้ามเวลาซูสแตนด์น้ำหนักเบาร้านค้าระดับโลกโจไทสถานะอะตอมเนื้อละเอียดแบบสอบถาม TanStack — สถานะเซิร์ฟเวอร์การดึงข้อมูล การแคช การซิงโครไนซ์ การรีเฟรชพื้นหลัง การอัพเดตในแง่ดีการตอบสนอง API, รายการแบ่งหน้า, ข้อมูลแบบเรียลไทม์ท้องถิ่นขอบเขตของรัฐทั่วโลกใช้สถานะบริบทซูสแตนด์โจไทรีดักซ์

ก่อนที่จะเข้าถึงห้องสมุดใดๆ คุณควรระบุให้ชัดเจนว่าคุณกำลังจัดการสถานะประเภทใด การรวมหมวดหมู่สถานะที่แตกต่างกันเป็นสาเหตุหลักของแอปพลิเคชัน React ที่ได้รับการออกแบบมากเกินไป

  • สถานะ UI ท้องถิ่น — ไม่ว่าดรอปดาวน์เปิดอยู่ แท็บใดที่ใช้งานอยู่ ค่าปัจจุบันของอินพุตที่ควบคุม สถานะนี้เป็นของคอมโพเนนต์เดียวหรือทรีย่อยขนาดเล็ก
  • สถานะไคลเอ็นต์ที่ใช้ร่วมกัน — ข้อมูลที่องค์ประกอบหลายรายการที่อาจอยู่ห่างไกลจำเป็นต้องอ่านหรือเขียน: ผู้ใช้ที่ได้รับการตรวจสอบสิทธิ์ในปัจจุบัน การตั้งค่าธีม ตะกร้าสินค้า
  • สถานะเซิร์ฟเวอร์ — ข้อมูลที่เริ่มต้นบนเซิร์ฟเวอร์ มีลักษณะไม่พร้อมกัน และจำเป็นต้องมีการตรวจสอบแคช การดึงข้อมูลพื้นหลังอีกครั้ง และการจัดการวงจรการโหลด/ข้อผิดพลาด
  • สถานะ URL — ตัวกรอง การแบ่งหน้า และคำค้นหาที่ควรรีเฟรชหน้าและแชร์ผ่านลิงก์ได้
  • สถานะแบบฟอร์ม — อินพุตที่ควบคุม ข้อผิดพลาดในการตรวจสอบ และสถานะการส่ง มักจะได้รับการจัดการที่ดีที่สุดโดยไลบรารีเฉพาะ เช่น React Hook Form

สิ่งเดียวที่มีผลกระทบมากที่สุดที่คุณสามารถทำได้คือต่อต้านความอยากที่จะเทรัฐทุกประเภทมาไว้ในร้านค้าระดับโลกแห่งเดียว แต่ละหมวดหมู่มีข้อกำหนดด้านความสอดคล้องที่แตกต่างกัน อายุการใช้งานที่แตกต่างกัน และความถี่ในการอัปเดตที่แตกต่างกัน

บริบท React: ตัวเลือกในตัว

บริบท API มาพร้อมกับ React และไม่จำเป็นต้องมีการขึ้นต่อกันเพิ่มเติม มันทำงานได้ดีสำหรับสถานะที่เปลี่ยนแปลงไม่บ่อยนักและถูกใช้โดยคอมโพเนนต์จำนวนมาก ตัวอย่างคลาสสิก ได้แก่ ธีม สถานที่ และอ็อบเจ็กต์ผู้ใช้ที่ได้รับการตรวจสอบสิทธิ์

// AuthContext.tsx
import { createContext, useContext, useState, ReactNode } from 'react';

interface AuthState {
  user: User | null;
  login: (credentials: Credentials) => Promise<void>;
  logout: () => void;
}

const AuthContext = createContext<AuthState | null>(null);

export function AuthProvider({ children }: { children: ReactNode }) {
  const [user, setUser] = useState<User | null>(null);

  const login = async (credentials: Credentials) => {
    const user = await authService.login(credentials);
    setUser(user);
  };

  const logout = () => setUser(null);

  return (
    <AuthContext.Provider value={{ user, login, logout }}>
      {children}
    </AuthContext.Provider>
  );
}

export function useAuth() {
  const ctx = useContext(AuthContext);
  if (!ctx) throw new Error('useAuth must be used inside AuthProvider');
  return ctx;
}

กับดักประสิทธิภาพบริบท

บริบทมีลักษณะการทำงานที่รู้จักกันดีซึ่งทำให้นักพัฒนาจำนวนมากต้องสะดุด กล่าวคือ ผู้บริโภคทุกรายจะแสดงผลซ้ำทุกครั้งที่การอ้างอิงค่าบริบทเปลี่ยนแปลง หากคุณจัดเก็บออบเจ็กต์ขนาดใหญ่และกลายพันธุ์บ่อยครั้งไว้ในบริบทเดียว คุณจะทริกเกอร์การเรนเดอร์ซ้ำโดยไม่จำเป็นทั่วทั้งแผนผังของคุณ

กลยุทธ์ในการลดผลกระทบ ได้แก่ :

  • แบ่งบริบทตามความถี่ในการอัปเดต เก็บออบเจ็กต์ผู้ใช้ไว้ในบริบทหนึ่งและการตั้งค่า UI ไว้ในบริบทอื่น
  • จดจำวัตถุค่าด้วย useMemo ดังนั้นการอ้างอิงจะเปลี่ยนแปลงเมื่อข้อมูลเปลี่ยนแปลงจริงเท่านั้น
  • ใช้ React.memo บนส่วนประกอบของผู้บริโภคเพื่อข้ามการเรนเดอร์ซ้ำเมื่ออุปกรณ์ประกอบฉากที่พวกเขาสนใจไม่มีการเปลี่ยนแปลง

ข้อสรุปที่ตรงไปตรงมาก็คือบริบทนั้นยอดเยี่ยมสำหรับสถานะทั่วโลกที่มีความถี่ต่ำ แต่ไม่ใช่โซลูชันการจัดการสถานะที่มีจุดประสงค์ทั่วไป เมื่อคุณพบว่าตัวเองกำลังเขียนบันทึกช่วยจำที่ซับซ้อนเพื่อแก้ไขพฤติกรรมการเรนเดอร์ซ้ำของ Context ก็ถึงเวลาที่จะต้องเข้าถึงห้องสมุดเฉพาะ

ชุดเครื่องมือ Redux: ตัวเลือกระดับองค์กรที่สมบูรณ์

ชุดเครื่องมือ Redux - การไหลของข้อมูลแบบทิศทางเดียวผู้สร้างแอคชั่นจัดส่งมิดเดิลแวร์thunk / saga / คนตัดไม้ลดร้านค้าแหล่งเดียวของความจริงตัวเลือกส่วนประกอบUI แสดงผลอีกครั้งจัดส่ง (การกระทำ)ผ่านประมวลผลการกระทำคืนสถานะใหม่ได้ข้อมูลมามุมมองการอัปเดตปฏิสัมพันธ์ของผู้ใช้Redux DevToolsการดีบักการเดินทางข้ามเวลาและการตรวจสอบสถานะ

Redux มีชื่อเสียงในด้านสำเร็จรูป — ชื่อเสียงที่ได้รับในยุคก่อนชุดเครื่องมือ Redux Toolkit (RTK) กำจัดพิธีการในขณะที่ยังคงรักษาสิ่งที่ทำให้ Redux มีประสิทธิภาพ: แผนผังสถานะเดียวที่คาดเดาได้และตรวจสอบได้พร้อมกระแสข้อมูลทิศทางเดียวที่เข้มงวด

เรือ RTK createSliceซึ่งสร้างผู้สร้างการกระทำและตัวลดจากคำจำกัดความเดียว และใช้ Immer ภายใต้ประทุนเพื่อให้คุณสามารถเขียนการกลายพันธุ์ที่ดูจำเป็น แต่นำไปใช้จริงอย่างไม่เปลี่ยนรูป

// features/cart/cartSlice.ts
import { createSlice, PayloadAction } from '@reduxjs/toolkit';

interface CartItem {
  id: string;
  name: string;
  quantity: number;
  price: number;
}

interface CartState {
  items: CartItem[];
  coupon: string | null;
}

const initialState: CartState = { items: [], coupon: null };

export const cartSlice = createSlice({
  name: 'cart',
  initialState,
  reducers: {
    addItem(state, action: PayloadAction<CartItem>) {
      const existing = state.items.find(i => i.id === action.payload.id);
      if (existing) {
        existing.quantity += action.payload.quantity;
      } else {
        state.items.push(action.payload);
      }
    },
    removeItem(state, action: PayloadAction<string>) {
      state.items = state.items.filter(i => i.id !== action.payload);
    },
    applyCoupon(state, action: PayloadAction<string>) {
      state.coupon = action.payload;
    },
  },
});

export const { addItem, removeItem, applyCoupon } = cartSlice.actions;
export default cartSlice.reducer;

แบบสอบถาม RTK: สถานะเซิร์ฟเวอร์ภายใน Redux

RTK จัดส่งคู่หูที่เรียกว่า RTK Query ซึ่งจัดการสถานะเซิร์ฟเวอร์โดยตรงภายในร้าน Redux โดยจะสร้างตะขอ React โดยอัตโนมัติจากคำจำกัดความปลายทางและจัดการแคช การทำให้ใช้งานไม่ได้ และการอัปเดตในแง่ดี

// services/productsApi.ts
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';

export const productsApi = createApi({
  reducerPath: 'productsApi',
  baseQuery: fetchBaseQuery({ baseUrl: '/api' }),
  tagTypes: ['Product'],
  endpoints: (builder) => ({
    getProducts: builder.query<Product[], void>({
      query: () => '/products',
      providesTags: ['Product'],
    }),
    updateProduct: builder.mutation<Product, Partial<Product>>({
      query: ({ id, ...patch }) => ({
        url: `/products/${id}`,
        method: 'PATCH',
        body: patch,
      }),
      invalidatesTags: ['Product'],
    }),
  }),
});

export const { useGetProductsQuery, useUpdateProductMutation } = productsApi;

Redux Toolkit เป็นตัวเลือกที่เหมาะสมเมื่อคุณต้องการการดีบักการเดินทางข้ามเวลาผ่าน Redux DevTools เมื่อหลายทีมจำเป็นต้องสนับสนุนโมเดลสถานะที่ใช้ร่วมกันพร้อมแบบแผนที่บังคับใช้ หรือเมื่อคุณมีตรรกะทางธุรกิจแบบ cross-slice ที่ซับซ้อนซึ่งได้รับประโยชน์จากมิดเดิลแวร์ เช่น redux-saga หรือ redux-observable.

Zustand: รัฐระดับโลกรุ่นไลท์เวทโดยไม่ต้องมีพิธีการ

Zustand ใช้แนวทางที่แตกต่างอย่างสิ้นเชิง ไม่มีผู้ให้บริการ ไม่มีตัวลด และไม่มีประเภทการดำเนินการ คุณกำหนดร้านค้าเป็นอ็อบเจ็กต์ JavaScript ธรรมดาด้วยสถานะและวิธีการ จากนั้นใช้งานด้วยฮุกเดียว API ทั้งหมดพอดีบนหน้าจอเดียว

// stores/useCartStore.ts
import { create } from 'zustand';
import { persist, devtools } from 'zustand/middleware';

interface CartStore {
  items: CartItem[];
  addItem: (item: CartItem) => void;
  removeItem: (id: string) => void;
  totalPrice: () => number;
  clear: () => void;
}

export const useCartStore = create<CartStore>()(
  devtools(
    persist(
      (set, get) => ({
        items: [],

        addItem: (item) =>
          set((state) => {
            const existing = state.items.find((i) => i.id === item.id);
            if (existing) {
              return {
                items: state.items.map((i) =>
                  i.id === item.id
                    ? { ...i, quantity: i.quantity + item.quantity }
                    : i
                ),
              };
            }
            return { items: [...state.items, item] };
          }),

        removeItem: (id) =>
          set((state) => ({ items: state.items.filter((i) => i.id !== id) })),

        totalPrice: () =>
          get().items.reduce((sum, i) => sum + i.price * i.quantity, 0),

        clear: () => set({ items: [] }),
      }),
      { name: 'cart-storage' }
    )
  )
);

การสมัครสมาชิกและประสิทธิภาพโดยละเอียด

Zustand แก้ปัญหาการเรนเดอร์ซ้ำของ Context ผ่านการสมัครสมาชิกตามตัวเลือก ส่วนประกอบจะแสดงผลซ้ำเมื่อส่วนของสถานะที่เลือกมีการเปลี่ยนแปลงเท่านั้น

// Only re-renders when items.length changes, not on price changes
const itemCount = useCartStore((state) => state.items.length);

// Only re-renders when the total changes
const total = useCartStore((state) => state.totalPrice());

ระบบนิเวศมิดเดิลแวร์ของ Zustand ครอบคลุมถึงความคงอยู่ localStorage, การรวม DevTools, การเปลี่ยนรูปแบบ Immer และการซิงค์ URL เป็นตัวเลือกที่เหมาะสำหรับทีมที่ต้องการความสามารถระดับ Redux โดยไม่ต้องเสียค่าติดตั้งระดับ Redux

Jotai: สถานะปรมาณูได้รับแรงบันดาลใจจากการหดตัว

แบบจำลอง Jotai ระบุเป็นกราฟของอะตอม ซึ่งเป็นหน่วยสถานะขนาดเล็กที่สามารถประกอบขึ้นได้ซึ่งสามารถหาได้จากกันและกัน โมเดลนี้มีประสิทธิภาพเป็นพิเศษสำหรับสถานะไดนามิก ลองนึกถึงรายการโหนดตัวแก้ไขโดยที่แต่ละโหนดมีสถานะการเลือก/โฟกัสที่เป็นอิสระของตัวเอง หรือรูปแบบที่ซับซ้อนซึ่งการมองเห็นฟิลด์ขึ้นอยู่กับค่าฟิลด์อื่น ๆ

// atoms/filterAtoms.ts
import { atom, selector } from 'jotai';

export const searchTermAtom = atom('');
export const categoryAtom = atom<string | null>(null);
export const productsAtom = atom<Product[]>([]);

// Derived atom — recomputes only when its dependencies change
export const filteredProductsAtom = atom((get) => {
  const products = get(productsAtom);
  const term = get(searchTermAtom).toLowerCase();
  const category = get(categoryAtom);

  return products.filter((p) => {
    const matchesTerm = p.name.toLowerCase().includes(term);
    const matchesCategory = category === null || p.category === category;
    return matchesTerm && matchesCategory;
  });
});
// ProductList.tsx
import { useAtom, useAtomValue } from 'jotai';

function ProductList() {
  const [searchTerm, setSearchTerm] = useAtom(searchTermAtom);
  const filtered = useAtomValue(filteredProductsAtom);

  return (
    <>
      <input value={searchTerm} onChange={(e) => setSearchTerm(e.target.value)} />
      {filtered.map((p) => <ProductCard key={p.id} product={p} />)}
    </>
  );
}

แบบจำลองปฏิกิริยาที่ละเอียดของ Jotai หมายความว่าเมื่อคำค้นหาเปลี่ยนแปลง จะมีเฉพาะส่วนประกอบที่สมัครเป็นสมาชิกเท่านั้น filteredProductsAtom แสดงผลอีกครั้ง ส่วนประกอบที่สมัครสมาชิกเท่านั้น categoryAtom ไม่ได้ถูกแตะต้อง สิ่งนี้ทำให้ Jotai เป็นเลิศสำหรับการใช้งานกับกราฟสถานะที่หนาแน่นและพึ่งพาซึ่งกันและกัน

TanStack Query: หน้าแรกที่เหมาะสมสำหรับสถานะเซิร์ฟเวอร์

TanStack Query (เดิมชื่อ React Query) ไม่ใช่ไลบรารีการจัดการสถานะทั่วไป แต่เป็นไลบรารีสถานะเซิร์ฟเวอร์และจัดการความรับผิดชอบนั้นได้ดีกว่าสิ่งอื่นใดในระบบนิเวศ โดยทั่วไปแล้ว การดึงข้อมูล การแคช การซิงโครไนซ์ และการอัปเดตข้อมูลระยะไกลใน React โดยไม่มี TanStack Query หมายถึงการจัดการการโหลดแฟล็ก อ็อบเจ็กต์ข้อผิดพลาด และการทำให้แคชใช้ไม่ได้ด้วยตนเองในสถานะท้องถิ่นหรือร้านค้าส่วนกลาง TanStack Query ทำทุกอย่างโดยอัตโนมัติ

// hooks/useProducts.ts
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';

export function useProducts(filters: ProductFilters) {
  return useQuery({
    queryKey: ['products', filters],
    queryFn: () => api.getProducts(filters),
    staleTime: 5 * 60 * 1000,   // treat data as fresh for 5 minutes
    gcTime: 10 * 60 * 1000,     // keep unused data in cache for 10 minutes
  });
}

export function useUpdateProduct() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: (update: ProductUpdate) => api.updateProduct(update),

    // Optimistic update
    onMutate: async (update) => {
      await queryClient.cancelQueries({ queryKey: ['products'] });
      const previous = queryClient.getQueryData(['products']);
      queryClient.setQueryData(['products'], (old: Product[]) =>
        old.map((p) => (p.id === update.id ? { ...p, ...update } : p))
      );
      return { previous };
    },

    onError: (_err, _update, context) => {
      queryClient.setQueryData(['products'], context?.previous);
    },

    onSettled: () => {
      queryClient.invalidateQueries({ queryKey: ['products'] });
    },
  });
}

อาร์เรย์คีย์แบบสอบถามคือการแคชแบบดั้งเดิมของ TanStack Query แบบสอบถามใด ๆ ที่ใช้คีย์เดียวกันร่วมกันจะใช้รายการแคชเดียวกัน เมื่อคุณทำให้คีย์ใช้ไม่ได้ ทุกองค์ประกอบที่สมัครรับคีย์นั้นจะถูกดึงข้อมูลอีกครั้งโดยอัตโนมัติในเบื้องหลังและอัปเดตเมื่อมีข้อมูลใหม่เข้ามา

การดึงข้อมูลล่วงหน้าและไฮเดรชั่นใน Next.js

ในแอปพลิเคชัน Next.js คุณสามารถดึงข้อมูลข้อความค้นหาล่วงหน้าบนเซิร์ฟเวอร์และแยกน้ำออกจากข้อมูล HTML เพย์โหลด ซึ่งช่วยลดการโหลดสปินเนอร์สำหรับการแสดงผลหน้าแรกโดยสิ้นเชิง

// app/products/page.tsx (Next.js App Router)
import { dehydrate, HydrationBoundary, QueryClient } from '@tanstack/react-query';

export default async function ProductsPage() {
  const queryClient = new QueryClient();
  await queryClient.prefetchQuery({
    queryKey: ['products', {}],
    queryFn: () => api.getProducts({}),
  });

  return (
    <HydrationBoundary state={dehydrate(queryClient)}>
      <ProductList />
    </HydrationBoundary>
  );
}

การรวมห้องสมุด: สถาปัตยกรรมเชิงปฏิบัติ

การใช้งานจริงมักจะได้ประโยชน์จากการรวมเครื่องมือหลายอย่างเข้าด้วยกัน โดยแต่ละเครื่องมือจะรับผิดชอบตามหมวดหมู่สถานะของตนเอง แอปพลิเคชัน React ขนาดกลางถึงใหญ่ที่มีโครงสร้างดีอาจมีลักษณะดังนี้:

  • แบบสอบถาม TanStack เป็นเจ้าของสถานะเซิร์ฟเวอร์ทั้งหมด มันดึงข้อมูลแคชและซิงโครไนซ์ข้อมูลระยะไกล ไม่มีสิ่งอื่นใดที่แตะการตอบสนอง API
  • ซูสแตนด์ เป็นเจ้าของสถานะไคลเอ็นต์ทั่วโลก เช่น ตะกร้าสินค้า เซสชันผู้ใช้ที่ได้รับการตรวจสอบสิทธิ์ การตั้งค่า UI และการประสานงานข้ามคุณลักษณะใดๆ ที่ซับซ้อนเกินไปสำหรับบริบท
  • บริบท React เป็นเจ้าของการกำหนดค่าแบบ low-churn — ธีมปัจจุบัน, สถานที่, แฟล็กคุณลักษณะ
  • useState / useReducer สถานะของคอมโพเนนต์ในเครื่องของตัวเอง — โมดอลเปิด/ปิด, ค่าฟิลด์ของฟอร์ม (หรือ React Hook Form สำหรับฟอร์มที่ซับซ้อน), การเลือกแท็บ
  • พารามิเตอร์การค้นหา URL สถานะการนำทางของตัวเอง — ตัวกรองที่ใช้งานอยู่ ลำดับการจัดเรียง หมายเลขหน้าปัจจุบัน

การแยกข้อกังวลนี้ไม่ใช่แค่ความสวยงามเท่านั้น หมายความว่าแคชสถานะเซิร์ฟเวอร์ของคุณจะไม่ถูกรบกวนด้วยสถานะ UI ร้านค้าไคลเอนต์ทั่วโลกของคุณจะไม่เต็มไปด้วยข้อมูลการตอบสนองที่ TanStack Query จะแคชได้อย่างมีประสิทธิภาพมากขึ้น และบริบทของคุณจะไม่ทริกเกอร์การเรนเดอร์ซ้ำทั้งแอปเนื่องจากมีผู้เก็บค่าที่เปลี่ยนแปลงอย่างรวดเร็วไว้ในนั้น

รูปแบบประสิทธิภาพที่ควรรู้

ตัวเลือกที่บันทึกไว้พร้อมกับการเลือกใหม่

เมื่อรับค่าที่คำนวณจากร้านค้า Redux ให้ใช้การเลือกใหม่เพื่อหลีกเลี่ยงการคำนวณใหม่ในการเรนเดอร์ทุกครั้ง RTK ส่งออกซ้ำ createSelector จากการเลือกใหม่

import { createSelector } from '@reduxjs/toolkit';

const selectItems = (state: RootState) => state.cart.items;

export const selectCartSummary = createSelector(selectItems, (items) => ({
  count: items.reduce((n, i) => n + i.quantity, 0),
  total: items.reduce((sum, i) => sum + i.price * i.quantity, 0),
}));

การแยกการเรนเดอร์ด้วย useTransition

React18's useTransition ให้คุณทำเครื่องหมายการอัปเดตสถานะว่าไม่เร่งด่วน เพื่อให้เบราว์เซอร์สามารถขัดจังหวะการอัปเดตเพื่อจัดการงานที่มีลำดับความสำคัญสูงกว่า เช่น อินพุตของผู้ใช้ สิ่งนี้มีประโยชน์อย่างยิ่งเมื่อการเปลี่ยนแปลงสถานะทำให้เกิดการเรนเดอร์ซ้ำซึ่งมีราคาแพง

const [isPending, startTransition] = useTransition();

const handleFilterChange = (value: string) => {
  startTransition(() => {
    setFilterValue(value); // expensive downstream re-render is deferrable
  });
};

หลีกเลี่ยงปัญหาเอกลักษณ์ของวัตถุ

แหล่งที่มาทั่วไปของการเรนเดอร์ Phantom อีกครั้งคือการสร้างออบเจ็กต์ใหม่หรือตัวอักษรอาร์เรย์ภายในการเรนเดอร์ useMemo and useCallback เป็นเครื่องมือของคุณที่นี่ แต่นำไปใช้เฉพาะเมื่อคุณมีหลักฐานของปัญหาด้านประสิทธิภาพเท่านั้น การจดบันทึกก่อนเวลาอันควรจะเพิ่มค่าใช้จ่ายด้านการรับรู้โดยไม่รับประกันผลประโยชน์

กรอบการตัดสินใจ

ใช้แผนผังการตัดสินใจต่อไปนี้เมื่อเลือกแนวทางการจัดการสถานะสำหรับคุณลักษณะใหม่:

  1. รัฐเป็นสถานะเฉพาะขององค์ประกอบเดียวหรือทรีย่อยขนาดเล็กหรือไม่ ใช้ useState หรือ useReducer.
  2. รัฐแสดงถึงข้อมูลที่ดึงมาจากเซิร์ฟเวอร์หรือไม่ ใช้ แบบสอบถาม TanStack.
  3. ลูกค้าทั่วโลกระบุว่ามีส่วนประกอบจำนวนมากในแผนผังต้องการหรือไม่ เข้าถึงเพื่อ ซูสแตนด์ เว้นแต่คุณจะอยู่ในโค้ดเบส Redux อยู่แล้ว
  4. สถานะเปลี่ยนแปลงน้อยครั้งและตอบสนองวัตถุประสงค์ในการกำหนดค่า (ธีม สถานที่) หรือไม่ ใช้ บริบท React.
  5. รัฐมีความเชื่อมโยงถึงกันอย่างมากกับคุณค่าที่ได้รับมามากมายหรือไม่? พิจารณา โจไท.
  6. คุณต้องการการแก้ไขข้อบกพร่องในการเดินทางข้ามเวลา โครงสร้างทางสถาปัตยกรรมที่เข้มงวด หรือเรื่องราวเกี่ยวกับอะซิงก์ที่ซับซ้อนหรือไม่? ใช้ ชุดเครื่องมือ Redux.

รูปแบบการต่อต้านทั่วไปที่ควรหลีกเลี่ยง

  • การจัดเก็บการตอบสนองของเซิร์ฟเวอร์ใน Redux หรือ Zustand ให้ TanStack Query เป็นเจ้าของข้อมูลนั้น การทำซ้ำในร้านค้าส่วนกลางจะสร้างข้อบกพร่องในการซิงโครไนซ์
  • รวบรวมทุกสิ่งไว้ในร้านค้าขนาดใหญ่เพียงแห่งเดียว สถานะที่ไม่เกี่ยวข้องซึ่งอยู่ในสไลซ์เดียวกันบังคับให้มีการมีเพศสัมพันธ์โดยไม่จำเป็น และทำให้การทดสอบยากขึ้น
  • การใช้บริบทสำหรับการอัพเดตความถี่สูง การเปลี่ยนแปลงค่าบริบททุกครั้งจะแสดงผลผู้บริโภคทั้งหมดอีกครั้ง สำหรับค่าที่เปลี่ยนแปลงในทุกการกดแป้นพิมพ์หรือเฟรมภาพเคลื่อนไหว บริบทเป็นเครื่องมือที่ไม่ถูกต้อง
  • ได้รับสถานะภายในส่วนประกอบ ค่าที่คำนวณซึ่งขึ้นอยู่กับสถานะควรเป็นตัวเลือกบันทึกหรืออะตอมที่ได้รับ ไม่ใช่การคำนวณแบบอินไลน์ที่ทำงานในทุกการเรนเดอร์
  • ละเว้นสถานะการโหลดและข้อผิดพลาด สถานะของเซิร์ฟเวอร์เป็นแบบอะซิงโครนัสโดยเนื้อแท้ พื้นผิวแบบสอบถาม TanStack isLoading, isErrorและ error สำหรับทุกคำถาม ใช้พวกเขา

บทสรุป

ภูมิทัศน์การจัดการของรัฐใน React ไม่เคยดีเท่านี้มาก่อน คุณไม่จำเป็นต้องเลือกระหว่างเฟรมเวิร์กที่หนักหน่วงกับการสร้างทุกอย่างตั้งแต่เริ่มต้นอีกต่อไป Redux Toolkit มอบความสามารถในการคาดการณ์ระดับองค์กรโดยไม่ต้องมีต้นแบบเหมือนรุ่นก่อน Zustand มอบพลังแบบเดียวกันนั้นด้วยการตั้งค่าเพียงเล็กน้อย Jotai แก้ปัญหายากๆ ด้วยกราฟสถานะไดนามิกที่มีรายละเอียดละเอียด และ TanStack Query ได้แก้ไขสถานะเซิร์ฟเวอร์อย่างแน่นอน — หากคุณยังคงจัดการการตอบสนอง API ใน useEffect and useStateคุณเป็นหนี้ตัวเองในการย้ายถิ่นฐาน

ข้อมูลเชิงลึกที่สำคัญที่สุดคือการจัดหมวดหมู่: ระบุสถานะที่คุณกำลังเผชิญอยู่ก่อน จากนั้นเลือกเครื่องมือที่ปรับให้เหมาะกับหมวดหมู่นั้น ต่อต้านสัญชาตญาณที่จะรวมทุกอย่างไว้ในระบบเดียว แนวทางแบบหลายชั้น — TanStack Query สำหรับสถานะเซิร์ฟเวอร์, Zustand สำหรับสถานะไคลเอนต์ทั่วโลก, บริบทสำหรับการกำหนดค่า และสถานะท้องถิ่นสำหรับทุกสิ่ง — สร้างฐานโค้ดที่ง่ายต่อการให้เหตุผล ทดสอบได้ง่ายขึ้น และบำรุงรักษาได้มากขึ้นเมื่อทีมและความต้องการเติบโตขึ้น