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';
。configureStore
和 createStore
的语法也稍有一些变化,详情可以参考官方文档。
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 会稍微麻烦一点,每个组件都需要实现 mapStateToProps
和 mapDispatchToProps
,并且末尾调用 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 使用小结的主要内容,如果未能解决你的问题,请参考以下文章
130242014051 《商品详情模块》需求分析与设计实验课小结
react-router与react-redux跳转后保存store数据(基于"react-router": "^2.8.0")