在React应用中使用Redux,redux toolkit的常用流程
为什么要使用Redux
Redux是一个集中的状态管理容器,可以对整个应用的状态进行统一管理。Redux的出现解决了Prop drilling的问题,尤其是当应用的组件层次较深或组件间共享状态较多时。
解决Prop drilling的问题
prop drilling(属性钻取):在React应用中需要通过组件层层传递props,才能到达目标子组件。而过程中传递props的有些组件可能并不需要该状态。导致代码的可维护性和可扩展性问题。
组件间的状态传递通常需要通过props来进行,可能会导致不必要的props传递链。因而需要上下文来统一管理某个需要传递或者共用的状态。而Redux提供了一个集中的全局的store集中存储所有状态,所有组件都可以直接从全局 store 访问到它们所需的状态,而不是依赖于 props 传递。
使用useState + Context进行状态管理
简单情况下,我们也可以使用React原生的useState进行简单的状态管理,这比较适合单一组件中的状态管理。也可以使用Context API对部分共享的状态提供简单的状态管理,比如对于主题theme的状态进行共享。
将 Context 放置在需要共享状态的组件的最近共同父组件中,可以确保只有相关的组件树部分访问和响应状态变化,从而提高效率。比如component1 和component2是兄弟组件,有共同的父组件componentParent ,那我们可以在componentParent这个父组件中设置Context进行状态共享。
import React, { useState } from 'react';
import ThemeContext from './ThemeContext';
import Component1 from './Component1';
import Component2 from './Component2';
const ComponentParent = () => {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
setTheme(theme === 'light' ? 'dark' : 'light');
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
<Component1 />
<Component2 />
<button onClick={toggleTheme}>Toggle Theme</button>
</ThemeContext.Provider>
);
};
export default ComponentParent;
相对于Context,Redux能对整个应用的状态进行集中的精细化管理,是个更加全面系统的状态管理工具。也是实现Flux架构的一种方式。
Redux 相关的库
1 redux
npm install redux
2 react-redux
用于在 React 应用中 Redux的集成。它提供了必要的 React 组件和钩子,比如Provider组件,钩子 useSelector 和 useDispatch(用于在函数组件中直接访问 Redux store 的状态和派发 actions)
npm install react-redux
3 Redux toolkit
Redux Toolkit 是 Redux 官方推荐的工具集,旨在简化 Redux 应用的构建过程。
RTK 提供了如 createSlice 和 createAsyncThunk 等 API,简化了 Redux 的用法,使得开发者可以更容易地定义 reducers、生成 action creators 和处理异步逻辑。
npm install @reduxjs/toolkit
4 涉及到异步操作使用redux-thunk or redux-saga
npm install redux-thunk
核心概念
1 状态 - store
Store是Redux的核心,负责存储整个应用的状态,使用reducer来对状态进行操作。
// ./src/store/index.js
import { configureStore } from "@reduxjs/toolkit";
import counterSlice from "./slices/counter/counterSlice";
const store = configureStore({
reducer: {
counter: counterSlice.reducer
},
});
export default store;
2 Provider
使用 Provider 组件来让整个应用可以访问到 Redux store。通常,你会在应用的最顶层组件中添加 Provider
import '@/styles/globals.css'
import type { AppProps } from 'next/app'
import { Provider } from 'react-redux'
import store from '@/store/index'
export default function App({
Component,
pageProps: { ...pageProps },
}: AppProps) {
return (
<Provider store={store}>
<main className='w-screen h-screen'>
<Component {...pageProps} />
</main>
</Provider>
)
}
3 在组件中进行状态修改和获取
在组件中,你可以使用 useSelector 钩子来读取 Redux store 的状态,使用 useDispatch 钩子来分发 actions,修改状态。
使用流程
这里的workflow主要涉及的是redux, react-redux, @reduxjs/toolkit三个库的使用,不涉及异步操作.
1 安装Redux Toolkit 和 React-Redux
npm install redux react-redux @reduxjs/toolkit
2 创建 Redux Store
// ./src/store/index.js
import { configureStore } from "@reduxjs/toolkit";
import counterSlice from "./slices/counter/counterSlice";
const store = configureStore({
reducer: {
counter: counterSlice.reducer
},
});
export default store;
3 用Provider包裹顶层组件
import '@/styles/globals.css'
import type { AppProps } from 'next/app'
import { Provider } from 'react-redux'
import store from '@/store/index'
export default function App({
Component,
pageProps: { ...pageProps },
}: AppProps) {
return (
<Provider store={store}>
<main className='w-screen h-screen'>
<Component {...pageProps} />
</main>
</Provider>
)
}
4 给状态创建相应的slice,添加reducer
// ./src/store/slices/counter/counterSlice.js
import { createSlice } from "@reduxjs/toolkit";
const counterSlice = createSlice({
name: "counter",
initialState: {
value:0,
},
reducers: {
increment: (state) => {
state.value += 1;
},
decrement: (state) => {
state.value -= 1;
},
},
});
export const { increment, decrement } = counterSlice.actions;
export default counterSlice;
5 在组件中改变状态(useDispatch),读取状态(useSelector)
useDispatch
允许你派发 actions,改变状态useSelector
允许你从 Redux Store 中读取状态
import React from "react";
import { useSelector, useDispatch } from "react-redux";
import { increment, decrement } from "./counterSlice";
const CounterComponent = () => {
const count = useSelector((state) => state.counter.value); // get value from store
const dispatch = useDispatch(); // dispatch will do actions to modify states in store
return (
<div>
<div>Count: {count}</div>
<button onClick={() => dispatch(increment())}>Increment</button>{" "}
{/* increment action */}
<button onClick={() => dispatch(decrement())}>Decrement</button>{" "}
{/* decrement action */}
</div>
);
};
export default CounterComponent;