首頁  >  文章  >  web前端  >  Reactjs 中的狀態管理:為您的專案選擇正確的狀態管理工具的指南

Reactjs 中的狀態管理:為您的專案選擇正確的狀態管理工具的指南

PHPz
PHPz原創
2024-07-21 08:19:19355瀏覽

State Management in Reactjs: A Guide to Choosing the Right State Management Tool for Your Projects

狀態管理在 React 應用程式中至關重要,因為它有助於追蹤應用程式資料。由於使用者介面 (UI) 是狀態的函數,因此確保應用程式的狀態始終是最新的至關重要。在本文中,您將了解如何選擇合適的狀態管理工具來滿足您的應用程式要求。

注意:本文適用於已經對 React 有一定了解但希望基於狀態管理為自己的 React 應用程式做出更好選擇的開發者。如果您還不了解 React,請查看文件開始學習。

了解狀態和狀態管理。

基於上述先決條件,您可能已經對 React 有了一些了解。但讓我們稍微回憶一下。

什麼是國家?

React 中的狀態是元件的內存,包含特定於該元件的資訊。用程式設計術語來說,狀態就是一個 JavaScript 對象,它只包含與元件相關的資料。

如前所述,React 中的 UI 直接受狀態影響。狀態的變化主要是由於使用者互動而發生的,例如按鈕點擊、滑鼠事件、輸入操作等。因此,管理應用程式中的狀態對於確保用戶根據其互動在螢幕上體驗最新的介面至關重要。

React 中的狀態管理。

當 React 元件的狀態改變時,會導致元件重新渲染。在此過程中,組件在幕後被銷毀並從頭開始重建。

大多數 React 應用程式在使用者與應用程式互動時都會經歷大量的狀態更新。使用最好的狀態管理技術來增強用戶體驗非常重要;畢竟,使用無響應的應用程式並不具有吸引力。想像一下,點擊 Instagram 應用程式上的「讚」按鈕,但它沒有響應。很煩吧?

言歸正傳,讓我們深入了解您可以為專案探索的不同狀態管理選項,解釋何時以及為何需要每個選項。

React 中的不同狀態管理選項。

有許多可用的狀態管理選項,但在本文中,我們將介紹一些最常用的選項,以滿足從小型到超大的各種規模的應用程式。我們將討論的選項包括:

  • React 內建鉤子
  • 上下文API
  • 第三方函式庫

React 內建鉤子用於狀態管理

React 提供了內建的鉤子來管理功能組件的狀態。這些鉤子易於使用,非常適合本地狀態管理。

本地狀態是僅一個組件所需的狀態,不會影響任何其他組件。

全域狀態是多個元件所需的狀態,我們也會在本文後面介紹如何管理它。

使用狀態鉤子

當然,函數式元件是無狀態的,但 React 引入了 useState 鉤子,使開發人員能夠將狀態變數添加到需要它們的元件中。

這個鉤子在元件的頂層調用,並傳入一個初始狀態值,它傳回一個目前值的陣列和一個 setter 函數。以下是如何使用它的程式碼範例:

import { useState} from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  return (
    dc6dce4a544fdca2df29d5ac0ea9906b
      e388a4556c0f65e1904146cc1a846beeYou clicked {count} times94b3e26ee717c64999d7867364b1b4a3
      5ddc0978355752d4bf828563dc007a14 setCount(count + 1)}>
        Click me
      65281c5ac262bf6d81768915a4a77ac0
    16b28748ea4df4d9c2150843fecfba68
  );
}

說明

  • 初始計數從 0 開始
  • 每當點擊按鈕時都會呼叫設定計數函數,從而始終使用最新值更新計數變數。

何時使用 useState 掛鉤

useState 鉤子非常適合在以下情況下管理元件中的狀態:

  • 本地狀態管理:狀態僅在單一元件內需要,不需要在多個元件之間共用。
  • 簡單狀態邏輯:狀態邏輯很簡單,例如切換值、計數器、表單輸入和簡單條件。
  • 有限的元件層次結構:狀態不需要深入傳遞多層元件,這可能會導致道具鑽探。
  • 小型專案:應用程式沒有需要更高階解決方案的廣泛狀態管理需求。

範例:

  • Managing form input values.
  • Toggling UI elements (e.g., show/hide).
  • Simple counters and trackers.

The useState hook provides a simple and efficient way to handle state for these scenarios, ensuring your components remain manageable and easy to understand.

useReducer Hook

The useReducer hook was introduced by the React team to handle complex state logic or case-sensitive updates. Here are the key parameters you need to keep in mind while using useReducer:

  1. reducer: This is the function where all the state updating code is executed. It takes the current state and an action as arguments and returns a new state.
  2. initialArg: This is the initial state that you declare from the onset.
  3. dispatch: This is the function called in the event handler. It is returned from the useReducer hook and is used to send actions to the reducer.
  4. state: This is the current state value also returned by the useReducer hook.

Here’s a code example of how to use this hook:

import React, { useReducer } from 'react';

const initialState = { count: 0 };

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      throw new Error();
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    dc6dce4a544fdca2df29d5ac0ea9906b
      e388a4556c0f65e1904146cc1a846beeCount: {state.count}94b3e26ee717c64999d7867364b1b4a3
      5ddc0978355752d4bf828563dc007a14 dispatch({ type: 'increment' })}>
        +
      65281c5ac262bf6d81768915a4a77ac0
      5ddc0978355752d4bf828563dc007a14 dispatch({ type: 'decrement' })}>
        -
      65281c5ac262bf6d81768915a4a77ac0
    16b28748ea4df4d9c2150843fecfba68
  );
}

Key Takeaways:

  1. Just like every other hook, useReducer must be called at the top level of the component.
  2. Every time the dispatch function is called, it triggers the reducer, leading to a state update depending on the action. This causes the component to re-render, maintaining the goal of keeping the UI and the current state in sync.
  3. You should only specify the action type in the dispatch function and a payload if need be.

When to Use the useReducer Hook

The useReducer hook is ideal for managing state in your components when:

  • Complex State Logic: The state logic is complex, involves multiple sub-values, or the next state depends on the previous state.
  • State Transition Management: When you need to handle multiple state transitions based on different actions.

Examples of Projects that Require useReducer

  • Complex forms: A multi-step form in a registration process.Each step of the form collects different data, and the state needs to be managed for all steps, with validation and submission logic.

  • Advanced to-do-list: A to-do list application with features like adding, removing, editing, and filtering tasks.

  • E-commerce cart management: An e-commerce site with a shopping cart that handles adding, removing, and updating item quantities.

State Management with Context API

The previously discussed options are great, but they come with a downside: the problem of prop drilling. Prop drilling occurs when a state needs to be passed down through multiple nested components from a parent to a child. This can lead to verbose and hard-to-maintain code, as each intermediary component needs to explicitly pass the state or function down the tree.Global state, which is the state needed by multiple components, becomes particularly challenging to manage with prop drilling.

To solve this problem, React introduced the Context API, which is used for managing global state. The Context API allows you to create a context object that can be accessed by any component within its provider, eliminating the need to pass props through intermediate components.

How to Use the Context API

Here’s a step-by-step guide on how to use it:

  1. Create a Context: First, create a context using the createContext function. This creates an object with a Provider and a Consumer.

    import React, { createContext } from 'react';
    const MyContext = createContext();
    
  2. Provide Context Value: Wrap the components that need access to the context with the Provider component. Pass the value you want to share as a prop to the Provider.

    function App() {
     const [state, setState] = useState("Hello, World!");
     return (
       <MyContext.Provider value={{ state, setState }}>
         <ChildComponent />
       </MyContext.Provider>
     );
    }
    
  3. Consume Context Value: This Use the context value in the child components by using the useContext hook or the Consumer component.

    import React, { useContext } from 'react';
    import MyContext from './path-to-context';
    function ChildComponent() {
     const { state, setState } = useContext(MyContext);
     return (
       <div>
         <p>{state}</p>
         <button onClick={() => setState("Context API is awesome!")}>
           Change Text
         </button>
       </div>
     );
    }
    

Example Usage

Here’s a complete example demonstrating how to use the Context API:

import React, { createContext, useState, useContext } from 'react';

// Create a context
const MyContext = createContext();

function App() {
  const [state, setState] = useState("Hello, World!");

  return (
    43ad9860753b01834247292615a2b05f
      88f9b25aeabe4ed8ddd63b3febe25d20
    8e66e6aff1f0a13ebced51b2c1b5d182
  );
}

function ChildComponent() {
  const { state, setState } = useContext(MyContext);

  return (
    dc6dce4a544fdca2df29d5ac0ea9906b
      e388a4556c0f65e1904146cc1a846bee{state}94b3e26ee717c64999d7867364b1b4a3
      5ddc0978355752d4bf828563dc007a14 setState("Context API is awesome!")}>
        Change Text
      65281c5ac262bf6d81768915a4a77ac0
    16b28748ea4df4d9c2150843fecfba68
  );
}

export default App;

Key Takeaways:

  1. 建立Context:createContext()用於建立Context對象,其中包括Provider和Consumer。
  2. 提供上下文:Provider 元件用於將當前上下文值傳遞給需要它的元件樹。
  3. 使用上下文:useContext 鉤子在功能元件中使用來存取上下文值。

何時使用上下文 API

Context API 非常適合需要在多個元件之間共用狀態或資料而無需在元件樹的每個層級傳遞 props 的場景。當處理全域狀態或狀態需要由深度嵌套的元件存取時,它特別有用。以下是 Context API 有益的一些具體案例:

  1. 主題

    • 範例:在整個應用程式中管理主題(淺色或深色模式)。
    • 詳細資訊:主題狀態在多個元件之間共享,確保 UI 一致地反映所選主題。
  2. 使用者驗證:

    • 範例:管理使用者驗證狀態和使用者資訊。
    • 詳細資訊:身份驗證狀態(登入/登出)和使用者資料(使用者名稱、角色等)需要透過各種元件訪問,例如標題、個人資料頁面和受保護的路由。
  3. 語言在地化:

    • 範例:在應用程式中處理多語言支援。
    • 詳細資訊:所選語言狀態和翻譯資料需要可供整個應用程式的文字渲染元件使用。
  4. 表單的複雜狀態管理:

    • 範例:跨多個表單欄位和元件共用表單資料和驗證狀態。
    • 詳細資訊:跨越多個步驟或組件的表單可以從追蹤輸入值和驗證錯誤的共用狀態中受益。

透過了解何時以及如何使用 Context API,您可以更有效地管理 React 應用程式中的全域狀態。這種方法有助於避免 prop 鑽探的陷阱,保持程式碼庫清潔和可維護,並有助於創建更強壯和可擴展的 React 應用程式。

用於狀態管理的第三方函式庫

第三方狀態管理庫提供了額外的工具和模式來有效地管理狀態,特別是在複雜的應用程式中。這些程式庫通常具有進階功能和最佳化,可增強 React 提供的內建狀態管理解決方案。一些最受歡迎的第三方狀態管理庫包括 Redux、MobX、Recoil 和 Zustand。

在本文中,我們將介紹 Redux。如果您需要使用提到的其他人,您可以查看他們的文檔;我將在本文末尾添加連結。不要感到不知所措,這些工具中的大多數都非常適合初學者。現在,讓我們直接進入 Redux!

使用 Redux 進行狀態管理

Redux 是一個第三方狀態管理庫,透過將所有狀態儲存在一個稱為 store 的中心位置,為 prop 鑽探和全域狀態管理提供了最佳解決方案。這意味著所有元件都可以獨立存取此狀態,無論它們在元件樹中的位置如何。

這是一個遊戲規則改變者,因為隨著應用程式變得越來越大並且有更多的狀態需要處理,有必要將其抽象化到一個地方。這種組織使我們的程式碼更乾淨,調試更容易。聽起來不錯,對吧?

請記住,Redux 並不特別限於 React;它是一個獨立的函式庫,可以與 Angular、Vue 等其他 JavaScript 框架整合。

如何在 React 中使用 Redux

在我們逐步了解使用 Redux 的過程之前,了解構成 Redux 基礎的關鍵概念非常重要:

  1. Store: The store is the central repository for an application's state. It holds the entire state tree and provides methods to access and update the state.
  2. Reducers: Reducers are pure functions that determine how the state changes in response to actions. They take the current state and an action as arguments and return a new state.
  3. Actions: Actions are plain JavaScript objects that describe what happened in the application. Each action has a type property and may include additional data.
  4. Action Creators: Action creators are functions that create and return action objects. They encapsulate the action creation logic, making the code more manageable.
  5. Dispatch: Dispatch is a function provided by the Redux store that sends actions to the store. It triggers reducers to process the action and update the state.

Understanding these concepts is essential to effectively implementing Redux in your React application.

How to Integrate and Use Redux in Your React Project

In this subsection, you will learn a step-by-step approach to integrating Redux with your React projects. We'll use a simple counter-example to illustrate the process. Here are the steps:

Setting up your Project

  • Create a React app with Vite:

     npm create vite@latest projectName
    
  • Navigate into your project directory:

     cd projectName
    
  • Install Redux Toolkit and React-Redux:

     npm install @reduxjs/toolkit react-redux
    
  1. Creating the Redux Store: Create a new file src/app/store.js and set up the Redux store:

     import { createStore } from 'redux';
     import rootReducer from '../features/counter/counterReducer';
    
     const store = createStore(rootReducer);
    
     export default store;
    
  2. Creating the Reducer: Create a new directory src/features/counter and inside it, create a file counterReducer.js:

     const initialState = {
       value: 0,
     };
    
     function counterReducer(state = initialState, action) {
       switch (action.type) {
         case 'INCREMENT':
           return { ...state, value: state.value + 1 };
         case 'DECREMENT':
           return { ...state, value: state.value - 1 };
         case 'INCREMENT_BY_AMOUNT':
           return { ...state, value: state.value + action.payload };
         default:
           return state;
       }
     }
    
     export default counterReducer;
    
  3. Creating Actions: In the same directory, create a file counterActions.js:

     export const increment = () => ({
       type: 'INCREMENT',
     });
    
     export const decrement = () => ({
       type: 'DECREMENT',
     });
    
     export const incrementByAmount = (amount) => ({
       type: 'INCREMENT_BY_AMOUNT',
       payload: amount,
     });
    
  4. Providing the Store to Your App: Wrap your application with the Redux Provider in src/main.jsx:

     import React from 'react';
     import ReactDOM from 'react-dom';
     import { Provider } from 'react-redux';
     import store from './app/store';
     import App from './App';
     import './index.css';
    
     ReactDOM.render(
       <Provider store={store}>
         <App />
       </Provider>,
       document.getElementById('root')
     );
    
  5. Connecting React Components to Redux: In your src/App.jsx, use the Redux state and dispatch actions:

     import React from 'react';
     import { useSelector, useDispatch } from 'react-redux';
     import { increment, decrement, incrementByAmount } from './features/counter/counterActions';
    
     function App() {
       const count = useSelector((state) => state.value);
       const dispatch = useDispatch();
    
       return (
         <div>
           <p>Count: {count}</p>
           <button onClick={() => dispatch(increment())}>+</button>
           <button onClick={() => dispatch(decrement())}>-</button>
           <button onClick={() => dispatch(incrementByAmount(2))}>+2</button>
         </div>
       );
     }
    
     export default App;
    

This is how to use Redux in your React applications. If you need to know more, you can check the documentation. However, Redux has introduced a more optimized way of writing Redux applications with Redux Toolkit (RTK).

Before RTK, the legacy Redux was the only way to use Redux. Now, we have Redux Toolkit with some optimized features, and that is what we will be covering in the next section.

How to Use Redux Toolkit in React

RTK introduces several key concepts that simplify state management. The major ones you need to know are:

  1. Slices: A slice is a collection of Redux reducer logic and actions for a single feature of your application. It streamlines the process of writing reducers and actions into a single unit.

  2. createSlice: This RTK function helps you create a slice, automatically generating action creators and action types. It reduces boilerplate code significantly.

  3. configureStore: This function simplifies the process of creating a Redux store by providing good defaults, including integration with the Redux DevTools Extension and middleware like redux-thunk.

  4. createAsyncThunk: This function is used for handling asynchronous logic. It generates actions and action creators to manage different stages of an asynchronous operation (e.g., pending, fulfilled, and rejected).

  5. Selectors: Functions that extract and derive pieces of state from the store. RTK encourages using selectors to encapsulate and reuse state logic.

  6. RTK Query: An advanced data fetching and caching tool built into RTK. It simplifies handling server-side data, reducing the need for boilerplate code related to data fetching, caching, and synchronization.

Understanding these concepts is essential for effectively implementing Redux Toolkit in your React application.

How to integrate and use Redux Toolkit in your React project

In this subsection, you'll learn a step-by-step approach to integrating Redux Toolkit with your React projects. We’ll use a simple counter example, similar to the one used in the plain Redux example, to highlight the improvements and optimizations Redux Toolkit offers. Here are the steps:

Setting up your Project

  • Create a React app with Vite:

     npm create vite@latest projectName
    
  • Navigate into your project directory:

     cd projectName
    
  • Install Redux Toolkit and React-Redux:

     npm install @reduxjs/toolkit react-redux
    
  1. Creating a Redux Slice: Create a new file for your slice (e.g., counterSlice.js):

     import { createSlice } from '@reduxjs/toolkit';
    
     const counterSlice = createSlice({
       name: 'counter',
       initialState: { count: 0 },
       reducers: {
         increment: (state) => {
           state.count += 1;
         },
         decrement: (state) => {
           state.count -= 1;
         },
       },
     });
    
     export const { increment, decrement } = counterSlice.actions;
     export default counterSlice.reducer;
    
  2. Configuring the Store: Create a new file for your store (e.g., store.js):

     import { configureStore } from '@reduxjs/toolkit';
     import counterReducer from './counterSlice';
    
     const store = configureStore({
       reducer: {
         counter: counterReducer,
       },
     });
    
     export default store;
    
  3. Providing the Store to Your App: Wrap your app with the Provider component in your main file (e.g., main.js or index.js):

     import React from 'react';
     import ReactDOM from 'react-dom';
     import { Provider } from 'react-redux';
     import store from './store';
     import App from './App';
    
     ReactDOM.render(
       <Provider store={store}>
         <App />
       </Provider>,
       document.getElementById('root')
     );
    
  4. Using Redux State and Actions in Your Components: Use the useSelector and useDispatch hooks in your component (e.g., Counter.js):

     import React from 'react';
     import { useSelector, useDispatch } from 'react-redux';
     import { increment, decrement } from './counterSlice';
    
     function Counter() {
       const count = useSelector((state) => state.counter.count);
       const dispatch = useDispatch();
    
       return (
         <div>
           <p>{count}</p>
           <button onClick={() => dispatch(increment())}>+</button>
           <button onClick={() => dispatch(decrement())}>-</button>
         </div>
       );
     }
    
     export default Counter;
    

Redux Toolkit (RTK) simplifies and optimizes the traditional Redux setup by reducing boilerplate code and integrating essential tools and best practices. While legacy Redux requires manual configuration and verbose code for actions and reducers, RTK offers a more streamlined approach with utility functions like configureStore, createSlice, and createAsyncThunk.

RTK includes built-in middleware, integrates seamlessly with Redux DevTools, and promotes a standard way of writing Redux logic, making state management in React applications more efficient and maintainable. If you need to use Redux, I recommend using the modern Redux Toolkit, as it is now recommended by Redux. You can check the docs to learn more about RTK.

When to Use Redux

Redux is a powerful state management library, but it isn't always necessary for every React application. Here are some scenarios when using Redux might be beneficial:

  1. Complex State Logic:

    • When your application has complex state logic that is difficult to manage with React's built-in hooks like useState and useReducer.
    • Example: An e-commerce application with multiple product filters, user authentication, and a shopping cart.
  2. Global State Management:

    • When you have state that needs to be accessed and updated by many components across different parts of your application.
    • Example: A user authentication system where user data needs to be accessible throughout the application.
  3. Consistent and Predictable State:

    • When you need a predictable state container that helps you debug and test your application more easily.
    • Example: A large-scale application where you need to maintain and track the state transitions clearly.
  4. DevTools Integration:

    • When you want to leverage powerful developer tools like Redux DevTools for tracking state changes and debugging.
    • Example: During development, Redux DevTools can help in understanding how the state changes in response to actions.

Conclusion

I hope by now you have gained more clarity and insights into choosing the right state management tool for your projects. We have covered tools that cater to both small and extremely large projects. With the knowledge gained from this article, you can now make more informed decisions for your projects. See you next time on another insightful topic.

Further reading and learning

  • Redux docs

  • Zustand docs

  • Mobx docs

  • Recoil docs

  • React docs

以上是Reactjs 中的狀態管理:為您的專案選擇正確的狀態管理工具的指南的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn