使用react-redux能让我们组件之间互相通信,并且相比较以前的写法,更加的简单明了。在使用前,我们需要npm install一下react-redux以及reduxjs/toolkit。
一、添加react-redux和reduxjs/toolkit
npm install react-redux
注意:如果找不到模块,再执行npm install @types/react-redux一下即可
详细内容可参考https://github.com/reduxjs/react-redux
npm install @reduxjs/toolkit
详细内容可参考https://www.npmjs.com/package/@reduxjs/toolkit
二、了解react-redux和reduxjs/toolkit的几个API
Provider:react-redux 提供Provider组件,可以让容器组件拿到state。
store :作为一个 prop 传给 Provider 组件。
useSelector:从redux的store对象中获取数据(state)。
使用方法:const result:any= useSelector(selector:Function,equalityFn?:Function)
useDispatch:返回redux store中对dispatch函数的引用。
使用方法:const dispatch = useDispatch() dispatch(方法)
configureStore():包装createStore以提供简化的配置选项和良好的默认值。它可以自动组合您的碎片,添加您提供的任何Redux中间件,默认情况下包括Redux -thunk,并支持使用Redux DevTools扩展。
三、开始撸redux的demo
1、创建store
首先在src文件夹下创建store文件夹,并创建index.ts文件。因为reduxjs/toolkit是碎片化,所以需要使用configureStore将碎片组合起来,以便维护。在index文件中的代码如下:
import { configureStore } from '@reduxjs/toolkit';
export default configureStore({
reducer: {
},
});
2、引入Provider,将store作为props传递给子组件
import { Provider } from 'react-redux' import store from '@src/store' ReactDOM.render( <Provider store={store}> <ConfigProvider locale={zh_CN}> <Route /> </ConfigProvider > </Provider>, document.getElementById('root') );
3、经典的计数器Demo
需求:数字的默认值为0,点击加1按钮,数字加1,减1按钮,数字减1。
首先,在store文件夹下创建一个counterSlice文件,并引入createSlice。
import { createSlice } from '@reduxjs/toolkit'
然后创建一个counterSlice碎片
export const counterSlice = createSlice({
name: 'counter', //碎片名称
initialState: { //碎片的默认值
value: 0,
},
reducers: { //方法
increment: (state) => { //增加1函数
state.value += 1;
},
decrement: (state) => { //减少1函数
state.value -= 1;
},
},
});
最后将increment,decrement添加到action,并且声明一个变量selectCount,导出这个碎片。
export const { increment, decrement } = counterSlice.actions;
export const selectCount = (state: any) => state.counter.value;
export default counterSlice.reducer;
注:将increment,decrement添加到action,外部可直接调用,并且会自动触发reducers,并且返回最新的state。
创建counterSlice碎片后,需要在store的index文件中,将这个碎片组合起来。
import { configureStore } from '@reduxjs/toolkit';
import counterSlice from './counterSlice'
export default configureStore({
reducer: {
counter: counterSlice //碎片的name:碎片
},
});
如何在我们需要的地方使用呢?这种情况下就需要使用useSelector和useDispatch了。完整的代码以及注释如下:
import React from 'react'; import { useSelector, useDispatch } from 'react-redux'; //引入useSelector以及useDispatch import { selectCount, increment, decrement } from '@src/store/counterSlice'; //引入counterSlice碎片中的变量以及函数
import { Button } from 'antd' export default () => { const count = useSelector(selectCount); //获取count的值,会随着按钮的点击而改变 const dispatch = useDispatch() return ( <div> <p>count的值是{count}</p> <Button onClick={() => dispatch(increment())}>加1</Button> //点击加1按钮时,触发increment <Button onClick={() => dispatch(decrement())}>减1</Button> //点击减1按钮时,触发decrement </div> ); }
到这,简单的一个demo就完成了。
四、优化计数器Demo
有时候需要请求接口之后,再执行其他操作,这就需要异步进行操作。下面来模拟一个简单的异步操作。
1、在reducers中添加需要的函数,并添加到action
incrementAsyncCount: (state, action) => {
// console.log(action) 输出结果: {type: "counter/incrementAsyncCount",payload: 1}
state.value += action.payload;
},
export const { incrementAsyncCount } = counterSlice.actions;
2、添加请求函数(使用延迟计时器模拟)
export const incrementAsync = (num: number) => (dispatch: any) => {
//可以在这里发送请求,当请求结束之后,再执行reducers
setTimeout(() => {
dispatch(incrementAsyncCount(num));
}, 2000);
};
3、在相应页面触发
import { incrementAsync } from '@src/store/counterSlice'; //首先引入该函数 <Button onClick={() => dispatch(incrementAsync(1))}>延迟2秒加1 </Button> //点击按钮时触发
这样设置完成之后,每次点击按钮,2秒之后,count的值才会加1。
五、完整Demo
import React from 'react'; import ReactDOM from 'react-dom'; import zh_CN from 'antd/es/locale/zh_CN'; import * as serviceWorker from './serviceWorker'; import { ConfigProvider } from 'antd'; import Route from '@src/router' import 'antd/dist/antd.css' import { Provider } from 'react-redux' import store from '@src/store' ReactDOM.render( <Provider store={store}> <ConfigProvider locale={zh_CN}> <Route /> </ConfigProvider > </Provider>, document.getElementById('root') ); serviceWorker.unregister();
import { configureStore } from '@reduxjs/toolkit';
import counterSlice from './counterSlice'
export default configureStore({
reducer: {
counter: counterSlice
},
});
import { createSlice } from '@reduxjs/toolkit';
export const counterSlice = createSlice({
name: 'counter',
initialState: {
value: 0,
},
reducers: {
increment: (state) => {
state.value += 1;
},
decrement: (state) => {
state.value -= 1;
},
incrementAsyncCount: (state, action) => {
// console.log(action) => {type: "counter/incrementAsyncCount",payload: 1}
state.value += action.payload;
},
},
});
export const { increment, decrement, incrementAsyncCount } = counterSlice.actions;
export const incrementAsync = (num: number) => (dispatch: any) => {
//可以在这里发送请求,当请求结束之后,再执行reducers
setTimeout(() => {
dispatch(incrementAsyncCount(num));
}, 2000);
};
export const selectCount = (state: any) => state.counter.value;
export default counterSlice.reducer;
import React, { useState } from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { selectCount, increment, decrement, incrementAsync } from '@src/store/counterSlice'; import { Button } from 'antd' export default () => { const count = useSelector(selectCount); const dispatch = useDispatch() return ( <div> <p>count的值是{count}</p> <Button onClick={() => dispatch(increment())}>加1</Button> <Button onClick={() => dispatch(decrement())}>减1</Button> <Button onClick={() => dispatch(incrementAsync(1))}>延迟2秒加1 </Button> </div> ); }