状態管理はアプリケーション データを追跡するのに役立つため、React アプリケーションでは非常に重要です。ユーザー インターフェイス (UI) は状態の関数であるため、アプリケーションの状態が常に最新であることを確認することが不可欠です。この記事では、アプリケーションの要件に合わせて適切な状態管理ツールを選択する方法を学びます。
注: この記事は、React についてすでにある程度の知識を持っているが、状態管理に基づいて React アプリケーションをより適切に選択したいと考えている開発者を対象としています。 React についてまだ知らない場合は、ドキュメントをチェックして学習を始めてください。
上記の前提条件に基づくと、おそらくすでに反応についてある程度の知識があるはずです。しかし、少し記憶を呼び起こしてみましょう。
React の状態はコンポーネントのメモリであり、そのコンポーネントに固有の情報が含まれています。プログラミング用語では、状態はコンポーネントに関するデータを単に含む JavaScript オブジェクトです。
前述したように、React の UI は状態に直接影響されます。状態の変化は主に、ボタンのクリック、マウス イベント、入力アクションなどのユーザー インタラクションによって発生します。したがって、ユーザーが操作に基づいて最新のインターフェイスを画面上で体験できるようにするには、アプリケーションの状態を管理することが不可欠です。
React コンポーネントの状態が変化すると、コンポーネントが再レンダリングされます。このプロセスでは、コンポーネントはバックグラウンドで破棄され、最初から再構築されます。
ほとんどの React アプリケーションでは、ユーザーがアプリを操作する際に多数の状態更新が発生します。ユーザー エクスペリエンスを向上させるには、最適な状態管理手法を使用することが重要です。結局のところ、応答しないアプリを使用するのは魅力的ではありません。 Instagram アプリで「いいね!」ボタンをクリックしても反応しないことを想像してください。迷惑ですよね?
これ以上は説明せずに、プロジェクトで検討できるさまざまな状態管理オプションについて詳しく説明し、それぞれのオプションがいつ必要になるのか、なぜ必要なのかを説明します。
利用可能な状態管理オプションは多数ありますが、この記事では、小規模から非常に大規模までのあらゆるサイズのアプリケーションに対応する、最も一般的に使用されるオプションのいくつかを取り上げます。ここで説明するオプションには以下が含まれます:
React は、機能コンポーネントで状態を管理するための組み込みフックを提供します。これらのフックは使いやすく、ローカルの状態管理に最適です。
ローカル状態 は、1 つのコンポーネントでのみ必要であり、他のコンポーネントには影響を与えない状態です。
グローバル状態 は、複数のコンポーネントに必要な状態であり、その管理方法についてもこの記事で後ほど説明します。
当然、機能コンポーネントはステートレスですが、React では useState フックを導入して、開発者が状態変数を必要とするコンポーネントに状態変数を追加できるようにしました。
このフックは、初期状態値が渡されてコンポーネントのトップレベルで呼び出され、現在の値の配列とセッター関数を返します。これを使用する方法のコード例を次に示します。
import { useState} from 'react'; function Counter() { const [count, setCount] = useState(0); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }
説明
useState フックは、次の場合にコンポーネントの状態を管理するのに最適です。
例:
The useState hook provides a simple and efficient way to handle state for these scenarios, ensuring your components remain manageable and easy to understand.
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:
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 ( <div> <p>Count: {state.count}</p> <button onClick={() => dispatch({ type: 'increment' })}> + </button> <button onClick={() => dispatch({ type: 'decrement' })}> - </button> </div> ); }
Key Takeaways:
The useReducer hook is ideal for managing state in your components when:
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.
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.
Here’s a step-by-step guide on how to use it:
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();
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> ); }
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 ( <MyContext.Provider value={{ state, setState }}> <ChildComponent /> </MyContext.Provider> ); } function ChildComponent() { const { state, setState } = useContext(MyContext); return ( <div> <p>{state}</p> <button onClick={() => setState("Context API is awesome!")}> Change Text </button> </div> ); } export default App;
Key Takeaways:
Context API は、コンポーネント ツリーのすべてのレベルで props を渡すことなく、複数のコンポーネント間で状態やデータを共有する必要があるシナリオに最適です。これは、グローバル状態を処理する場合、または深くネストされたコンポーネントによって状態にアクセスする必要がある場合に特に役立ちます。 Context API が有益な具体的なケースをいくつか示します:
テーマ:
ユーザー認証:
言語ローカリゼーション:
フォームの複雑な状態管理:
Context API をいつどのように使用するかを理解することで、React アプリケーションのグローバル状態をより効率的に管理できます。このアプローチは、プロップドリルの落とし穴を回避し、コードベースをクリーンで保守しやすく保ち、より堅牢でスケーラブルな React アプリケーションの作成に貢献します。
サードパーティの状態管理ライブラリは、特に複雑なアプリケーションで状態を効率的に管理するための追加のツールとパターンを提供します。これらのライブラリには、多くの場合、React が提供する組み込みの状態管理ソリューションを強化する高度な機能と最適化が付属しています。最も人気のあるサードパーティの状態管理ライブラリには、Redux、MobX、Recoil、Zustand などがあります。
この記事では、Redux について説明します。言及されている他のものを使用する必要がある場合は、そのドキュメントを確認してください。この記事の最後にリンクを追加します。これらのツールのほとんどは非常に初心者に優しいものなので、圧倒される必要はありません。さあ、Redux に早速入ってみましょう!
Redux はサードパーティの状態管理ライブラリであり、すべての状態をストアと呼ばれる中央の場所に保存することで、プロップ ドリルとグローバル状態管理に最適なソリューションを提供します。これは、コンポーネント ツリー内の位置に関係なく、すべてのコンポーネントが独立してこの状態にアクセスできることを意味します。
アプリケーションが大きくなり、処理する状態が増えるにつれて、それを 1 か所に抽象化することが不可欠になるため、これは大変革です。この構成により、コードがよりクリーンになり、デバッグが容易になります。素晴らしいですね。
Redux は特に React に限定されているわけではないことに留意してください。これは、Angular、Vue などの他の JavaScript フレームワークと統合できる独立したライブラリです。
Redux を使用する段階的なプロセスに入る前に、Redux の基礎を形成する重要な概念を理解することが重要です。
Understanding these concepts is essential to effectively implementing Redux in your React application.
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
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;
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;
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, });
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') );
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.
RTK introduces several key concepts that simplify state management. The major ones you need to know are:
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.
createSlice: This RTK function helps you create a slice, automatically generating action creators and action types. It reduces boilerplate code significantly.
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.
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).
Selectors: Functions that extract and derive pieces of state from the store. RTK encourages using selectors to encapsulate and reuse state logic.
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.
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
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;
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;
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') );
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.
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:
Complex State Logic:
Global State Management:
Consistent and Predictable State:
DevTools Integration:
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.
Redux docs
Zustand docs
Mobx docs
Recoil docs
React docs
以上がReactjs の状態管理: プロジェクトに適切な状態管理ツールを選択するためのガイドの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。