除了redux之外,还有两种中间件(Redux-thunk和Redux-saga)和常用组件(React-Redux),虽然用redux可以解决遇到的问题,但是学习这几种会使开发事半功倍
一、Redux-thunk
Redux-thunk 是Redux最常用的插件。什么时候会用到这个插件呢?比如在Dispatch一个Action之后,到达reducer之前,进行一些额外的操作,就需要用到middleware(中间件)。在实际工作中你可以使用中间件来进行日志记录、创建崩溃报告,调用异步接口或者路由。 这个中间件可以使用是Redux-thunk来进行增强(当然你也可以使用其它的),它就是对Redux中dispatch的加强。
(一)安装
npm install --save redux-thunk
(二)案例——计数器【异步累加】
1、在index.js中
// 引入createStore对象
import {
createStore ,applyMiddleware,compose} from 'redux'
// 引入中间件redux-thunk
import thunk from "redux-thunk"
// 引入reducer
import reducer from './reducer'
// 利用compose创造一个增强函数
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
}):compose
// 通过增强函数,把thunk引入进来
const enhancer = composeEnhancers(applyMiddleware(thunk))
// const store = createStore(
// reducer,
// window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
// );
const store = createStore(reducer,enhancer)
export default store;
2、统一管理action中的type,actionTypes.js
export const ASYNC_ADD_NUM_FN = "asyncAddNumFn";
export const JIAN = "jian";
3、统一管理action,actionCreator.js
import {
ADD, JIAN, DEL_LIST_ITEM } from './actionTypes'
// 以异步累加举例
//export const asyncAddNumFn = (data) => {
// return {
// type: 'ASYNC_ADD_NUM_FN',
// value: data
// }
//}
// 以高阶函数的形式书写
export const asyncAddNumFn = (data) => {
return (dispatch) => {
setTimeout(() => dispatch({
type: ASYNC_ADD_NUM_FN, value: data }), 2000)
}
}
// 计数器的减法
export const jianFnAction = () =>{
return {
type:JIAN
}
}
4、在reducer.js中
import {
JIAN,ASYNC_ADD_NUM_FN } from './actionTypes'
const initState={
num:0
}
// 导出一个函数,用于返回state
export default (state = initState, action) => {
let newState = JSON.parse(JSON.stringify(state)); // 对原本的state做一次深拷贝
console.log(action);
switch(action.type){
case JIAN:
newState.num -=1;
return newState;
case ASYNC_ADD_NUM_FN:
newState.num +=action.value;
return newState;
default:
break;
}
return newState;
}
5、页面中
import React, {
Component } from 'react'
import store from '../redux';
import {
addFnAction, jianFnAction,asyncAddNumFn} from '../redux/actionCreator'
export default class Count1 extends Component {
state = {
num:0
}
constructor(p){
super(p)
this.state={
num:0
}
this.state = store.getState()
store.subscribe(this.storeChange.bind(this))
console.log("11",this.state);
}
storeChange(){
this.setState(
store.getState()
)
}
render() {
return (
<div>
<Add/>
{
this.state.num}
<Jian/>
</div>
)
}
}
// 子组件1加
class Add extends Component {
add=()=>{
// console.log("jia ");
// store.dispatch(addFnAction())
// redux-thunk会自动注入dispatch给actionCreators
store.dispatch(asyncAddNumFn(1))
}
render() {
return (
<div onClick={
this.add.bind(this)}>加1</div>
)
}
}
// 子组件2减
class Jian extends Component {
jian=()=>{
console.log("jian");
store.dispatch(jianFnAction())
}
render() {
return (
<div onClick={
this.jian.bind(this)}>减1</div>
)
}
}
运行之后会发现其效果了,加法是异步执行的。
6、特别说明
如果使用以下代码,在页面中派发事件的时候就会比较麻烦,需要套一个promise
export const asyncAddNumFn = (data) => {
return {
type: ASYNC_ADD_NUM_FN,
value: data
}
}
因此将这个setTimeout转移到actionCreator中,见上面第3点
二、Redux-saga
redux-saga 是 redux 一个中间件,用于解决异步问题。redux-saga基于ES6的Generator, github地址.
Saga的 redux-saga/effects 中有几个关键字:
fork:创建一个新的进程或者线程,并发发送请求。
call:发送 api 请求
put:发送对应的 dispatch,触发对应的 action
takeEvery:监听对应的 action,每一次 dispatch 都会触发
takeLatest:监听对应的 action,只会触发最后一次 dispatch
all:跟 fork 一样,同时并发多个 action,没有顺序。
由于redux-thunk与redux-saga两者作用大致相同,但redux-saga需要基于generator,写起来也较为复杂,这里只做个概念普及,有兴趣的可以自行查阅文档学习。
三、React-Redux
React-Redux 这是一个React生态中常用组件,它可以简化 Redux 流程,其实就是简化版的 Redux
(一)安装
npm install --save react-redux
npm install --save redux
(二)提供器与连接器
1、Provider提供器
是一个提供器,只要使用了这个组件,组件里边的其它所有组件都可以使用 store 了,这也是React-redux的核心组件了。简单的说:凡是放在 中的组件,都可以获取到store中的数据。一般来说,提供器直接写在根组件。
2、connect连接器
需要在组件中使用连接器和react相连,获取数据
(三)案例——计数器
1、在index.js中
// 引入createStore对象
import {
createStore} from 'redux'
// 引入reducer
import reducer from './reducer'
const store = createStore(reducer);
export default store;
2、在reducer.js中
const initState={
num:0
}
// 导出一个函数,用于返回state
export default (state = initState, action) => {
let newState = JSON.parse(JSON.stringify(state)); // 对原本的state做一次深拷贝
switch(action.type){
case "add_count":
newState.num +=action.value;
return newState;
default:
break;
}
return newState;
}
3、入口函数中 index.js
使用提供器包裹,并提供store
import React from 'react';
import ReactDOM from 'react-dom/client';
import ReactRedux from './view/ReactRedux'
import {
Provider } from 'react-redux'
import store from './redux/index'
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<Provider store={
store}>
<ReactRedux />
</Provider>
</React.StrictMode>
);
4、页面
通过connect链接,引入了两种映射, 做到了删除了store的引入,增加了连接器与映射关系
import React from 'react'
import {
connect} from 'react-redux' //引入连接器
function ReactRedux(props) {
return (
<div>
<h2>{
props.num}</h2>
<button onClick={
props.addFn}>增加</button>
</div>
)
}
// stateToProps是一种映射关系,把原来的state映射成组件中的props属性
const stateToProps = (state)=>{
return {
num : state.num
}
}
// dispatchToPros也是一种映射,用于传递并修改数据,这里要返回一个对象并包含一个事件
const dispatchToPros = (dispatch)=>{
return {
addFn(){
dispatch({
type:"add_count",
value:1
})
}
}
}
export default connect(stateToProps,dispatchToPros)(ReactRedux);
(四)redux 和 react-redux的区别
1、概念
redux是react中进行state状态管理的JS库(并不是react插件),一般是管理多个组件中共享数据状态。这个是和Vuex是一样的。
React-Redux是Redux的官方React绑定库。它能够使你的React组件从Redux store中读取数据,并且向store分发actions以更新数据。
2、使用
redux和组件进行对接的时候是直接在组件中进行创建。
react-redux是运用Provider将组件和store对接,使在Provider里的所有组件都能共享store里的数据,还要使用connect将组件和react连接。
3、获取state的方式不一样
redux获取state是直接通过store.getState()。
react-redux获取state是通过mapStateToProps函数,只要state数据变化就能获取最新数据
4、触发action的方式不一样
redux是使用dispatch直接触发,来操作store的数据。
react-redux是使用mapDispathToProps函数然后在调用dispatch进行触发