原文链接:Redux+React
Redux
一、快速入门
Redux 是一个用于管理 JavaScript 应用程序状态的开源库。它广泛用于 React 应用程序中,但也可以与其他 JavaScript 框架一起使用,如Vue、Angular。Redux 旨在使状态管理更可预测、可维护和可扩展。
安装
npm install redux react-redux
yarn add redux react-redux
在 React 应用中,使用 Redux 通常是在以下场景下有益的:
- 共享状态:如果多个组件需要访问相同的状态数据,Redux 可以将这些状态中心化,以便在整个应用程序中共享和更新状态。
- 跨组件通信:当你需要在不同的组件之间传递数据或触发动作,Redux 提供了一种统一的方式来实现跨组件通信,而不需要通过多层嵌套传递 props。
- 持久化数据:如果你需要在应用程序刷新或导航时保留应用状态,Redux 可以与持久化库(如 Redux Persist)一起使用,以便在本地存储中保存状态数据。
- 中间件支持:Redux 支持中间件,这意味着你可以在处理动作时执行额外的逻辑,例如异步数据获取、日志记录、路由导航等。
Redux原理图
**
二、使用步骤
步骤 1: 安装 Redux
首先,你需要安装Redux和React-Redux。可以使用npm或者yarn:
# 使用 npm
npm install redux react-redux
# 使用 yarn
yarn add redux react-redux
步骤 2: 创建 Redux Store
在应用的主文件(index.js
)中创建Redux store。Redux store是整个应用状态的容器。
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import rootReducer from './redux/reducers'; // 你的根 reducer
import App from './App';
const store = createStore(rootReducer); // 创建 store
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
步骤 3: 创建 Reducers
Reducers 定义了应用状态的修改方式。每个 reducer 函数都接收先前的状态和一个 action,返回新的状态。
// src/redux/reducers.js
import { combineReducers } from 'redux';
import countReducer from './countReducer'; // 你的 reducer
const rootReducer = combineReducers({
count: countReducer, // 将所有的 reducer 放在这里
});
export default rootReducer;
步骤 4: 创建 Action Creators
Action creators 是用来创建 action 的函数。Action 是一个带有type
属性的普通 JavaScript 对象,它描述了发生了什么。
// src/redux/actions.js
export const increment = (data) => ({ type:'INCREMENT' , data })
export const decrement = (data) => ({ type:'DECREMENT' , data })
步骤 5: 创建 Reducer 函数
Reducer 函数根据接收到的 action 的类型来更新应用的状态。
// countReducer.js
const countReducer = (preState = 0, action) => {
const { type , data } = action
switch (type ) {
case 'INCREMENT':
return preState + data;
case 'DECREMENT':
return preState - data;
default:
return state;
}
};
export default countReducer;
步骤 6: 在 React 组件中使用 Redux
在 React 组件中,你可以使用connect
函数连接组件与 Redux store。
// CountComponent
import React from 'react';
import {connect} from 'react-redux';
import {increment, decrement} from '../../redux/actions'; // 引入 action creators
const CountComponent = ({count, increment, decrement}) => {
return (
<div>
<h1>Count: {count}</h1>
<button onClick={() => increment(10)}>Increment</button>
<button onClick={() => decrement(5)}>Decrement</button>
</div>
);
};
const mapStateToProps = (state) => {
return {
count: state.count, // 这里的 example 对应 rootReducer 中的 key
};
};
export default connect(mapStateToProps, {increment, decrement})(CountComponent);
步骤 7: 在 React 类式组件中使用 Redux
import React, {Component} from 'react';
import {connect} from 'react-redux';
import {increment, decrement} from '../redux/actions';
class Count extends Component {
render() {
return (
<div>
<h1>Count: {this.props.count}</h1>
<button onClick={this.props.increment}>Increment</button>
<button onClick={this.props.decrement}>Decrement</button>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
count: state.count, // 这里的example对应rootReducer中的key
};
};
export default connect(mapStateToProps, {increment, decrement})(Count);
三、异步Action
在React中使用Redux实现异步操作通常需要使用中间件,最常见的中间件是redux-thunk
。redux-thunk
允许你在Redux action creators中返回函数而不仅仅是普通的action对象,这个函数可以进行异步操作。以下是在React中使用Redux实现异步操作的一般步骤:
步骤 1: 安装redux-thunk
首先,你需要安装redux-thunk中间件。
# 使用 npm
npm install redux-thunk
# 使用 yarn
yarn add redux-thunk
步骤 2: 配置Redux Store
在创建Redux store时,需要将redux-thunk中间件添加到store中。通常,你会在创建store的文件中配置中间件。
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import {Provider} from 'react-redux';
import {createStore, applyMiddleware} from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './redux/reducers'; // 你的根 reducer
const store = createStore(rootReducer, applyMiddleware(thunk)); // 创建 store
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Provider store={store}>
<App/>
</Provider>
);
步骤 3: 创建异步Action Creators
现在,你可以创建异步action creators。这些action creators返回一个函数
,而不是一个简单的action对象。这个函数接收dispatch
参数,允许你手动分派action。
// actions.js
import {INCREMENT, DECREMENT, ASYNC_DECREMENT} from "./action-type-const";
export const increment = data => ({type: INCREMENT, data})
export const decrement = data => ({type: DECREMENT, data})
// 分发已经定义好的 Action
export const asyncIncrement = (data, time) => {
return (dispatch) => {
setTimeout(() => {
dispatch(increment(data))
}, time)
}
}
// 自定义分发 Action
export const asyncDecrement = (data, time) => {
return (dispatch) => {
setTimeout(() => {
dispatch({type: ASYNC_DECREMENT, data})
}, time)
}
}
步骤 4: 创建Reducer
import {INCREMENT, DECREMENT, ASYNC_DECREMENT} from "./action-type-const";
const initState = 0
const countReducer = (preState = initState, action) => {
const {data, type} = action
switch (type) {
case INCREMENT:
return preState + data
case DECREMENT:
return preState - data
case ASYNC_DECREMENT:
return preState - data
default:
return preState
}
}
export default countReducer
步骤 5: 使用异步Action Creators
在React组件中,你可以使用异步action creators来触发异步操作。这些action creators会分派一系列action来表示操作的不同阶段(例如请求开始、成功或失败)。
import {Component} from "react";
import {connect} from "react-redux";
import {increment, decrement, asyncIncrement, asyncDecrement} from "../../redux/actions";
class Count extends Component {
render() {
return (
<div>
<h1>当前count:{this.props.count}</h1>
<button onClick={() => this.props.increment(100)}>+100</button>
<br/>
<button onClick={() => this.props.decrement(59)}>-59</button>
<br/>
<button onClick={() => this.props.asyncIncrement(39, 2000)}>异步+39</button>
<br/>
<button onClick={() => this.props.asyncDecrement(75, 1000)}>异步-75</button>
<br/>
</div>
)
}
}
export default connect((state) => ({
count: state.count
}), {increment, decrement, asyncIncrement, asyncDecrement})(Count)
四、Redux Toolkit
Redux Toolkit 是官方推荐的编写 Redux 逻辑的方法。它围绕 Redux 核心,并包含对于构建 Redux 应用必不可少的软件包和功能。Redux Toolkit ,简化了大多数 Redux 任务,防止了常见错误,并使编写 Redux 应用程序更加容易。
步骤 1:安装 Redux Toolkit
# NPM
npm install @reduxjs/toolkit react-redux
# Yarn
yarn add @reduxjs/toolkit react-redux
步骤 2: 创建Toolkit的Slice
在Redux Toolkit中,状态管理通过Slice来定义。一个Slice包括了状态的初始值、Reducer函数以及可以自动处理的Action创建函数。action.payload
是 Redux 中的一个约定,它通常用来传递操作(action)所需的数据。在 Redux Toolkit 中,action.payload
是一个操作的有效负载,用于在 reducer 中更新状态。
创建一个Slice。例如,counterSlice.js
:
import {createSlice} from "@reduxjs/toolkit";
const countSlice = createSlice({
name: 'count',
initialState: {
count: 0
},
reducers: {
increment: (state, action) => {
state.count += action.payload;
},
decrement: (state, action) => {
state.count -= action.payload;
},
}
})
export const {increment, decrement} = countSlice.actions;
export default countSlice.reducer;
步骤 3:配置Redux Store
在应用中创建Redux Store,将Slice的Reducer添加到Store中。例如,store.js
:
// store.js
import {configureStore} from "@reduxjs/toolkit";
import countReducer from './count'
const store = configureStore({
reducer: {
count: countReducer
}
})
export default store
步骤 4:提供Redux Store到应用
在React应用的顶层组件index.js,使用
`组件提供Redux Store:
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import {Provider} from 'react-redux'
import store from "./store/store";
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Provider store={store}>
<React.StrictMode>
<App/>
</React.StrictMode>
</Provider>
);
步骤 5:在组件中使用Redux状态
在React组件中,可以使用useSelector
来选择Redux状态,以及useDispatch
来分发Redux动作。例如:
import React from 'react';
import {useSelector, useDispatch} from 'react-redux';
import {increment, decrement} from '../store/count';
function Counter() {
const count = useSelector((state) => state.count.count);
const dispatch = useDispatch();
return (
<div>
<p>Counter: {count}</p>
<button onClick={() => dispatch(increment(1))}>Increment</button>
<button onClick={() => dispatch(decrement(1))}>Decrement</button>
</div>
);
}
export default Counter;
步骤 6:在类组件中使用Redux状态
// src/components/Counter.js
import React from 'react';
import {connect} from 'react-redux';
import {increment, decrement} from '../store/count';
class Counter2 extends React.Component {
render() {
return (
<div>
<p>Count: {this.props.count}</p>
<button onClick={() => this.props.increment(5)}>+5</button>
<button onClick={() => this.props.decrement(5)}>-5</button>
</div>
);
}
}
const mapStateToProps = (state) => ({
count: state.count.count,
});
const mapDispatchToProps = {increment, decrement};
export default connect(mapStateToProps, mapDispatchToProps)(Counter2);
五、Redux Toolkit异步操作
步骤 1:设置 Redux Store
Redux Toolkit 简化了 Redux 在 React 应用中的使用,包括异步操作的处理。Redux Toolkit 提供了 createAsyncThunk
函数来轻松地处理异步操作,它接受两个参数:
typePrefix
(字符串):typePrefix
是一个用于创建 action type 的前缀字符串,通常以描述 action 的方式命名。Redux Toolkit 会自动为你生成三个 action types,分别对应于异步操作的不同状态:typePrefix/pending
、typePrefix/fulfilled
和typePrefix/rejected
。payloadCreator
(函数):payloadCreator
是一个异步函数,它包含了实际的异步操作逻辑,例如从服务器获取数据。payloadCreator
函数会在异步 action 被调用时执行,并且返回一个 Promise。当 Promise 被解决时,Redux Toolkit 会根据解决的值生成一个包含payload
属性的 action。这个payload
属性包含了异步操作的结果数据,通常是一个对象或数组。
import {createAsyncThunk, createSlice} from "@reduxjs/toolkit";
// 创建一个异步 thunk action
export const asyncIncrement = createAsyncThunk("async/increment", async () => {
const response = await fetch('/api/todos');
return await response.json();
})
const countSlice = createSlice({
name: 'count',
initialState: {
count: 0
},
reducers: {
increment: (state, action) => {
state.count += action.payload;
},
decrement: (state, action) => {
state.count -= action.payload;
},
},
extraReducers: (builder) => {
builder
.addCase(asyncIncrement.pending, (state) => {
console.log("asyncIncrement 正在执行中")
})
.addCase(asyncIncrement.fulfilled, (state, action) => {
console.log(action)
})
.addCase(asyncIncrement.rejected, (state, action) => {
console.log("asyncIncrement 出错了")
})
}
})
export const {increment, decrement} = countSlice.actions;
export default countSlice.reducer;
步骤 2:使用Redux Store
import React from 'react';
import {useSelector, useDispatch} from 'react-redux';
import {increment, decrement, asyncIncrement} from '../store/count';
function Counter() {
const count = useSelector((state) => state.count.count);
const dispatch = useDispatch();
return (
<div>
<p>Counter: {count}</p>
<button onClick={() => dispatch(increment(1))}>Increment</button>
<button onClick={() => dispatch(decrement(1))}>Decrement</button>
<button onClick={() => dispatch(asyncIncrement(1))}>异步+1</button>
</div>
);
}
export default Counter;
六、Redux Persist数据持久化
Redux Toolkit 是一个用于简化 Redux 开发的工具集,而 Redux Persist 是一个用于在 Redux 中实现数据持久化的库。当你想要将它们与 React 一起使用时,可以按照以下步骤进行配置:
步骤1:安装必要的库
# 使用 npm
npm install @reduxjs/toolkit react-redux redux-persist
# 使用 yarn
yarn add @reduxjs/toolkit react-redux redux-persist
步骤2:创建CounterSlice和UserSlice
import {createSlice} from "@reduxjs/toolkit";
const counterSlice = createSlice({
name: 'count',
initialState: {
count: 0
},
reducers: {
increment: (state, action) => {
state.count += action.payload
},
decrement: (state, action) => {
state.count -= action.payload
}
}
})
export const {increment, decrement} = counterSlice.actions
export default counterSlice.reducer
// userSlice
import {createSlice} from "@reduxjs/toolkit";
const userSlicer = createSlice({
name: 'user',
initialState: {
name: 'jvyou'
},
reducers: {
update: (state) => {
state.name += '@'
}
}
})
export const {update} = userSlicer.actions
export default userSlicer.reducer
步骤3:组合所有的Reducer
使用combineReducers
将所有的reducer
组合在一起,创建store/rootReducers
:
import {combineReducers} from "redux";
import CounterReducer from '@/store/CounterSlice.ts'
import UserReducer from "@/store/UserSlicer.ts";
// 指定类型,方便代码提示
const rootReducer = combineReducers<{count,user}>({
count: CounterReducer,
user: UserReducer
})
export default rootReducer
步骤3:创建 Redux store
使用 Redux Toolkit 的 configureStore
函数来创建 Redux store。在创建 store 的同时,配置 Redux Persist 的 persistReducer
。
import {configureStore} from "@reduxjs/toolkit";
import rootReducer from "@/store/RootReducer.ts";
import {persistReducer, persistStore} from 'redux-persist';
import storage from 'redux-persist/lib/storage';
const persistConfig = {
key: 'root',
storage,
whitelist: ['count'], // 只持久化 CounterReducer
};
const persistedReducer = persistReducer(persistConfig, rootReducer);
// 将所有的 Reducer 交给 persistedReducer 管理
export const store = configureStore({
reducer: {
pr: persistedReducer
},
// 其他配置项
middleware: getDefaultMiddleware => getDefaultMiddleware({
//关闭redux序列化检测
serializableCheck: false
})
});
export const persistor = persistStore(store);
export type StateType = ReturnType<typeof store.getState>;
上述代码中,persistConfig
是 Redux Persist 的配置,用于指定持久化的关键信息和存储引擎。persistReducer
将根 reducer 包装起来,以便在其中应用持久化。
步骤4:在应用中使用 Redux Provider
在应用的顶层组件中使用 Redux Provider,并传入上一步创建的 store
。
// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { PersistGate } from 'redux-persist/integration/react';
import App from './App';
import { store, persistor } from './app/store';
ReactDOM.render(
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<App />
</PersistGate>
</Provider>,
document.getElementById('root')
);
PersistGate
用于在加载过程中显示加载状态,直到持久化完成。
步骤5:组件使用 Redux
在 React 组件中使用 react-redux
提供的 useSelector
和 useDispatch
钩子,就像在普通的 Redux 应用中一样,刷新之后,count值不变,user的name被重置。
import React from 'react';
import {Button} from "antd";
import {decrement, increment} from "@/store/CounterSlice.ts";
import {useDispatch, useSelector} from "react-redux";
import {StateType} from "@/store";
import {update} from "@/store/UserSlicer.ts";
const Home: React.FC = () => {
const count = useSelector((state: StateType) => state.pr.count.count)
const user = useSelector((state: StateType) => state.pr.user)
const dispatch = useDispatch();
return (
<div>
<h1>Home</h1>
<h1>{count}</h1>
<Button onClick={() => dispatch(increment(100))}>+100</Button>
<Button onClick={() => dispatch(decrement(100))}>-100</Button>
<hr/>
{user.name}
<Button onClick={() => dispatch(update())}>更新姓名</Button>
</div>
);
};
export default Home;
通过以上步骤,你就配置好了 Redux Toolkit、React 和 Redux Persist 的集成,实现了数据的持久化。确保你的 reducer 和持久化的配置是正确的,以便在应用启动时从存储中恢复状态。
七、Redux开发者工具
Redux开发者工具的使用步骤如下:
在Chrome安装 Redux 开发者工具
安装依赖:
npm i redux-devtools-extension
yarn add redux-devtools-extension
在 store 中引入 devtools:
import {createStore, applyMiddleware} from "redux";
import thunk from "redux-thunk";
import rootReducer from "./redux/reducers";
import {composeWithDevTools} from 'redux-devtools-extension'
const store = createStore(rootReducer, composeWithDevTools(applyMiddleware(thunk)))