使用react-redux

  使用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:碎片
    },
  });

   如何在我们需要的地方使用呢?这种情况下就需要使用useSelectoruseDispatch了。完整的代码以及注释如下:

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();
入口文件index
import { configureStore } from '@reduxjs/toolkit';
import counterSlice from './counterSlice'
export default configureStore({
  reducer: {
    counter: counterSlice
  },
});
store文件index.ts
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;
store文件couterSlice.ts
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>
  );
}
ReduxTest页面

 

  

posted @ 2020-05-20 19:44  MinorF_γ  阅读(441)  评论(0编辑  收藏  举报