react-redux 使用小结

Posted GoldenaArcher

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了react-redux 使用小结相关的知识,希望对你有一定的参考价值。

react-redux 使用小结

好久没写 Redux 了,最近老板让写一个 POC 去把现在的 usecase+repo 的结构转成 redux,所以就……复习一下。这里的案例用的是 react-redux,原生 redux 的笔记可以参考一下这个:一文快速上手 Redux

functional based component

functional component 真的方便很多,因为不需要考虑 state 和 props 的 mapping……

store 以及 index.js 的配置也放在这里一起写了:

store:

这里用的是最新的 @reduxjs/toolkit,如果项目比较老的话,没有用最新版本的 react-redux 和 redux,就得用 import createStore from 'redux';configureStorecreateStore 的语法也稍有一些变化,详情可以参考官方文档。

import  configureStore  from '@reduxjs/toolkit';

const counterReducer = (state =  counter: 0 , action) => 
  if (action.type === 'increment') 
    return  counter: state.counter + 1 ;
   else if (action.type === 'decrement') 
    return  counter: state.counter - 1 ;
  

  return state;
;

const stroe = configureStore(
  reducer: counterReducer,
);

export default stroe;

index.js:

主要用来挂载 store,也可以挂在 App level。

import React from 'react';
import ReactDOM from 'react-dom/client';
import  Provider  from 'react-redux';

import './index.css';
import App from './App';
import store from './store';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <Provider store=store>
    <App />
  </Provider>
);

Counter:

这里实现的也就是一个 counter 的功能:

import  useDispatch, useSelector  from 'react-redux';
import classes from './Counter.module.css';

const Counter = () => 
  const dispatch = useDispatch();
  // useSelector 接受一个函数,用来返回 redux 中需要抠出来的状态
  const counter = useSelector((state) => state.counter);

  const incrementHandler = () => 
    dispatch( type: 'increment' );
  ;

  const decrementHandler = () => 
    dispatch( type: 'decrement' );
  ;

  const toggleCounterHandler = () => ;

  return (
    <main className=classes.counter>
      <h1>Redux Counter</h1>
      <div className=classes.value>counter</div>
      <div>
        <button onClick=incrementHandler>increment</button>
        <button onClick=decrementHandler>decrement</button>
      </div>
      <button onClick=toggleCounterHandler>Toggle Counter</button>
    </main>
  );
;

export default Counter;

页面如下:

class based component

class based component 会稍微麻烦一点,每个组件都需要实现 mapStateToPropsmapDispatchToProps,并且末尾调用 connect 这个 HOC 进行组件内 state 和 props 的 mapping。

import React,  Component  from 'react';
import  connect  from 'react-redux';
import classes from './Counter.module.css';

export class Counter extends Component 
  incrementHandler() 
    this.props.increment();
  
  decrementHandler() 
    this.props.decrement();
  
  toggleCounterHandler() 
  render() 
    const  counter  = this.props;
    return (
      <main className=classes.counter>
        <h1>Redux Counter</h1>
        <div className=classes.value>counter</div>
        <div>
          <button onClick=this.incrementHandler.bind(this)>increment</button>
          <button onClick=this.decrementHandler.bind(this)>decrement</button>
        </div>
        <button onClick=this.toggleCounterHandler>Toggle Counter</button>
      </main>
    );
  


// connect is a HOC
const mapStateToProps = (state) => 
  return 
    counter: state.counter,
  ;
;

const mapDispatchToProps = (dispatch) => 
  return 
    increment: () => dispatch( type: 'increment' ),
    decrement: () => dispatch( type: 'decrement' ),
  ;
;

export default connect(mapStateToProps, mapDispatchToProps)(Counter);

我记得以前项目配置过不需要进行 mapping 来着……抽空的时候回忆一下看看能不能记一下

添加 payload

有些情况下需要在组件内部向 reducer 中传值,这里就用 functional component 来实现了。class based component 以前都是封装好了的,一下子还真的有点想不起来怎么做……

const Counter = () => 
  const increaseHandler = () => 
    dispatch( type: 'increase', amount: 5 );
  ;
;
const counterReducer = (state =  counter: 0 , action) => 
  if (action.type === 'increase') 
    return  counter: state.counter + action.amount ;
  
;

添加多个状态

store 的修改:

import  configureStore  from '@reduxjs/toolkit';

const initialState = 
  counter: 0,
  showCounter: true,
;

const counterReducer = (state = initialState, action) => 
  if (action.type === 'increment') 
    return 
      counter: state.counter + 1,
      showCounter: state.showCounter,
    ;
   else if (action.type === 'decrement') 
    return 
      counter: state.counter - 1,
      showCounter: state.showCounter,
    ;
   else if (action.type === 'increase') 
    return 
      counter: state.counter + action.amount,
      showCounter: state.showCounter,
    ;
   else if (action.type === 'toggle') 
    return 
      showCounter: !state.showCounter,
      counter: state.counter,
    ;
  
  return state;
;

const stroe = configureStore(
  reducer: counterReducer,
);

export default stroe;

对比起来内部调用就方便很多了:

const Counter = () => 
    const showCounter = useSelector((state) => state.showCounter);

    return (
        showCounter && <div className=classes.value>counter</div>
    )

redux 的状态是不可变的,因此在使用老版的操作就需要返回一个新的状态,而不能直接修改原有的状态。

redux toolkit 部分更新

找了一下资料,突然发现之前的写法已经落伍了……

但是写都写好了就懒得删除了……

所以这里对 toolkit 的配置进行一下更新。

使用 toolkit 的优点包括:

  • 可以直接对状态进行修改

    toolkit 内部会进行监听,如果察觉到状态被修改了,那么 toolkit 内部会创建一个新的状态并进行返回。也就意味着对于开发来说,就少一个状态需要进行手动管理。

  • 少些很多代码

    不需要额外设立一个变量去监听对应的 type

    reducers 直接可以归并为可调用的函数,也不用反复写很多的 switch/if-else 流程控制

store 部分代码:

import  configureStore, createSlice  from '@reduxjs/toolkit';

const initialState = 
  counter: 0,
  showCounter: true,
;

const counterSlice = createSlice(
  name: 'counter',
  initialState: initialState,
  reducers: 
    increment(state) 
      // 可以直接进行修改
      state.counter++;
    ,
    decrement(state) 
      state.counter--;
    ,
    increase(state, action) 
      state.counter += action.payload;
    ,
    toggle(state) 
      state.showCounter = !state.showCounter;
    ,
  ,
);

const stroe = configureStore(
  reducer: counterSlice.reducer,
);

// 这样只要导出一个actions即可
// 虽然也可以说自己再封装一下,不过使用toolkit可以少写一写封装的代码也方便很多
export const counterActions = counterSlice.actions;

export default stroe;

Counter 部分代码:

import  useDispatch  from 'react-redux';
import  useSelector  from 'react-redux';
// 可以直接导入action并且在下面函数中调用,省了调用一些 type 的烦恼
import  counterActions  from '../store';
import classes from './Counter.module.css';

const Counter = () => 
  const dispatch = useDispatch();
  const counter = useSelector((state) => state.counter);
  const showCounter = useSelector((state) => state.showCounter);

  const incrementHandler = () => 
    dispatch(counterActions.increment());
  ;

  const increaseHandler = () => 
    dispatch(counterActions.increase(5)); //  type: SOME_UNIQUE_VALUE, payload: 10 
  ;

  const decrementHandler = () => 
    dispatch(counterActions.decrement());
  ;

  const toggleCounterHandler = () => 
    dispatch(counterActions.toggle());
  ;

  return (
    <main className=classes.counter>
      <h1>Redux Counter</h1>
      showCounter && <div className=classes.value>counter</div>
      <div>
        <button onClick=incrementHandler>increment</button>
        <button onClick=increaseHandler>Increase By 5</button>
        <button onClick=decrementHandler>decrement</button>
      </div>
      <button onClick=toggleCounterHandler>Toggle Counter</button>
    </main>
  );
;

export default Counter;

toolkit 管理多个状态

store 部分代码:

对于 store 来说就是创建多个 slice,并且在 configureStore 中合并创建 slices 的 reducers。

import  configureStore, createSlice  from '@reduxjs/toolkit';

const initialCounterState = 
  counter: 0,
  showCounter: true,
;

const counterSlice = createSlice(
  name: 'counter',
  initialState: initialCounterState,
  reducers: 
    increment(state) 
      state.counter++;
    ,
    decrement(state) 
      state.counter--;
    ,
    increase(state, action) 
      state.counter += action.payload;
    ,
    toggle(state) 
      state.showCounter = !state.showCounter;
    ,
  ,
);

const initialAuthState = 
  isAuthenticated: false,
;

const authSlice = createSlice(
  name: 'auth',
  initialState: initialAuthState,
  reducers: 
    login(state) 
      state.isAuthenticated = true;
    ,
    logout(state) 
      state.isAuthenticated = false;
    ,
  ,
);

const stroe = configureStore(
  reducer:  counter: counterSlice.reducer, auth: authSlice.reducer ,
);

export const counterActions = counterSlice.actions;
export const authActions = authSlice.actions;

export default stroe;

counter:

const Counter = () => 
  const dispatch = useDispatch();
  const  counter, showCounter  = useSelector((state) => state.counter);
;

这里需要注意就是,如果不使用解构,那么就会直接获得 counter 这个 slice 中包含的状态:

以上是关于react-redux 使用小结的主要内容,如果未能解决你的问题,请参考以下文章

react-redux 中的奇怪按钮行为

关于redux和react-redux

130242014051 《商品详情模块》需求分析与设计实验课小结

react-router与react-redux跳转后保存store数据(基于"react-router": "^2.8.0")

Python 3.6 列表元组操作小结

linux权限详情