redux使用详解

Posted 一杯清泉

tags:

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

        一个状态管理的JS库,用于数据的共享。结构如下:

安装:

yarn add redux

一、简化版的redux

1、src/reducer/store.js

//引入createStore
import createStore from 'redux'
//引入服务的reducer
import reducer from "./reducer";

export default createStore(reducer)

2、src/reducer/reducer.js

const defaultState = 
    count: 0


const reducer = (preState = defaultState, action) => 
    const type, data = action
    switch (type) 
        case 'add':
            return 
                count: preState.count + data
            
        case 'reduce':
            return 
                count: preState.count - data
            
        default:
            return defaultState
    


export default reducer

3、src/reducer/App.js

import React, Component from 'react';
import Button from 'antd'
import 'antd/dist/antd.css'
//用于获取状态
import store from "./reducer/store";

export default class App extends Component 

    componentDidMount() 
        //reducer不会触发页面变化,需要state来触发
        store.subscribe(() =>
            this.setState(store.getState())
        )
    

    render() 
        //获取reducer数据
        const count = store.getState()
        return (
            <div>
                <Button type='primary' onClick=this.reduce>-</Button>
                <span>count</span>
                <Button type='primary' onClick=this.add>+</Button>
            </div>
        );
    

    reduce = () => 
        //通知reducer页面数据变化了
        store.dispatch(
            type: 'reduce',
            data: 1
        )
    

    add = () => 
        //通知reducer页面数据变化了
        store.dispatch(
            type: 'add',
            data: 1
        )
    

二、完整版的redux

1、为了防止type被多个js引用,不小心写错,引发报错,需要将type设置为常量,创建src/reducer/typeCreators.js文件:

export const ADD = 'add_type'
export const REDUCE = 'reduce_type'

2、创建src/reducer/actionCreators.js文件。统一抽取action:

import ADD, REDUCE from "./typeCreators";

export const addAction = (data) => (
    
        type: ADD,
        data
    
)

export const reduceAction = (data) => (
    
        type: REDUCE,
        data
    
)

三、redux 的异步action

        如果action是一个对象,则是同步action;如果action是一个function,这是一个异步action,直接使用action返回函数redux不允许,直接报错,redux认识返回一个对象的action,如下方式是不被允许的:

import store from "./store";

/**
 * 异步加的action:返回的是函数,直接使用这种方式会报错
 */
export const addActionAsync = (data, time) => 
    return ()=>
        setTimeout(()=>
            store.dispatch(addAction(data))
        ,time)
    

        这是需要使用一个中间件来实现异步的的功能,即:redux-thunk。

四、redux-thunk实现异步action

yarn add redux-thunk

1、src/reducer/store.js

import createStore,applyMiddleware from 'redux'
import thunk from "redux-thunk";
import reducer from "./reducer";

/**
 * 该文件用于暴露一个store对象
 */
export default createStore(reducer, applyMiddleware(thunk))

        这时候直接运行addActionAsync就不会报错了。

        addActionAsync本身执行在store中,返回值默认有一个参数dispatch,不需要额外的引入,可以简化为

/**
 * 简化版
 */
export const addActionAsync = (data, time) => 
    return (dispatch) => 
        setTimeout(() => 
            //异步任务一般在函数内都会调用同步action
            dispatch(addAction(data))
        , time)
    

        异步action不是一个必须的需求,异步任务可放在action中执行,也可以放在组件中执行。

五、react-redux

yarn add react-redux

        redux是非官方的,使用其他也没啥问题,由于比较好用,官方又集成了redux,推出react-redux,用法更为灵活。如下模型图:

六、react-redux基本使用

  • UI组件:一般放在components文件夹下
  • 容器组件:一般放在container文件夹下

1、src/components/count/index.jsx:

export default class CountUI extends Component 

    render() 
        console.log('UI组件接收到的props:', this.props)
        return (
            <div>
                <Button type='primary' onClick=this.reduce>-</Button>
                <span>this.props.count</span>
                <Button type='primary' onClick=this.add>同步+1</Button>
                <Button type='primary' onClick=this.addAsync>异步+2</Button>
            </div>
        );
    

    reduce = () => 
        this.props.reduce(10)
    

    add = () => 
        this.props.add(5)
    

    addAsync = () => 
        this.props.addActionAsync(2, 500)
    

2、src/containers/count/index.jsx:

//引入UI组件
import CountUI from "../../components/count";
//引入connect用于连接UI组件和redux
import connect from "react-redux";
//引入action
import 
    addAction,
    reduceAction,
    addActionAsync
 from "../../reducer/actionCreators";

//----->状态
function mapStateToProps(state) 
    return 
        count: state.count
    


//----->操作状态的方法
function mapDispatchToProps(dispatch) 
    return 
        add: number => dispatch(addAction(number)),
        reduce: number => dispatch(reduceAction(number)),
        addActionAsync: (number, time) => dispatch(addActionAsync(number, time))
    


//使用connect创建并暴露一个count的容器组件
export default connect(mapStateToProps, mapDispatchToProps)(CountUI)
  • mapStateToProps

1、mapStateToProps函数返回一个对象

2、返回的key作为传递给UI组件的props的key,value作为UI组件props的value

3、mapStateToProps用于传递状态

  • mapDispatchToProps

mapDispatchToProps函数返回一个对象

返回的key作为传递给UI组件的props的key,value作为UI组件props的value

mapDispatchToProps用于传递状态的方法

七、react-redux优化使用

1、mapDispatchToProps简写

const mapStateToProps = state => (count: state.count)

//mapDispatchToProps一般写法
const mapDispatchToProps = dispatch => (
    add: number => dispatch(addAction(number)),
    reduce: number => dispatch(reduceAction(number)),
    addActionAsync: (number, time) => dispatch(addActionAsync(number, time))
);

//mapDispatchToProps精简写法,react-redux可以自动调用dispatch完成分发
const mapDispatchToProps = 
    add: addAction,
    reduce: reduceAction,
    addActionAsync: addActionAsync
;

//参数1:映射状态
//参数2:映射状态的操作方法
export default connect(mapStateToProps, mapDispatchToProps)(CountUI)

        即:mapDispatchToProps既可以当做函数,也可以当做对象。

2、无需自己给组件设置store,只需要给外壳设置

import store from "./reducer/store";
import Provider from "react-redux";

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

3、容器组件和UI组件合而为一,将connect写在UI组件的外面

src/containers/count/index.jsx:

import React, Component from 'react';
import connect from "react-redux";
import Button from 'antd'
import 'antd/dist/antd.css'
import 
    addAction,
    reduceAction,
    addActionAsync
 from "../../reducer/actionCreators";

class Count extends Component 

    render() 
        return (
            <div>
                <Button type='primary' onClick=this.reduce>-</Button>
                <span>this.props.count</span>
                <Button type='primary' onClick=this.add>同步+1</Button>
                <Button type='primary' onClick=this.addAsync>异步+2</Button>
            </div>
        );
    

    reduce = () => 
        this.props.reduce(10)
    

    add = () => 
        this.props.add(5)
    

    addAsync = () => 
        this.props.addActionAsync(2, 500)
    


const mapStateToProps = state => (count: state.count)

const mapDispatchToProps = 
    add: addAction,
    reduce: reduceAction,
    addActionAsync: addActionAsync
;

export default connect(mapStateToProps, mapDispatchToProps)(Count)

4、使用react-redux之后不需要自己使用store.subscribe检查redux中状态改变了,容器组件自动完成。

八、combineReducers

        当有多个reducer时候,需要将reducer合并成一个,否则createStore只接受一个reducer,其他的reducer就没有引入,这时候用到combineReducers:

import createStore, applyMiddleware, combineReducers from 'redux'
import thunk from "redux-thunk";
import countReducer from "./count/reducer";
import personReducer from "./person/reducer";

//所有的reducer保存为一个reducer
const allReducer = combineReducers(
    c: countReducer, //count可以根据需求任意命名,比如:c,haha,shu等等
    p: personReducer
)

export default createStore(allReducer, applyMiddleware(thunk))

        在容器组件中使用的时候:

const mapStateToProps = state => 
    //注意这块有个c,需要和combineReducers中的对应
    return count: state.c.count

        还可以简化,引入reducer.js:

import countReducer from "../reducers/count";
import personReducer from "../reducers/person";
import combineReducers from "redux";

//所有的reducer保存为一个reducer
export default combineReducers(
    c: countReducer, //count可以根据需求任意命名,比如:c,haha,shu等等
    p: personReducer
)

        在store.js中:

import createStore, applyMiddleware from 'redux'
import thunk from "redux-thunk";
import composeWithDevTools from 'redux-devtools-extension';
import allReducer from "./reducers";

export default createStore(allReducer, composeWithDevTools(applyMiddleware(thunk)))

九、react-redux项目结构分类

有时候containers也可以为components包,没有强制要求。 

redux其他使用案例参考:

react-redux实现todolist功能_一杯清泉的博客-CSDN博客

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

React - Redux Hooks的使用细节详解

Redux——详解

ide机构原创作品"生命火种"——清泉人参果品牌剖析

无论在寄存器中输入啥,使用 react-redux 和 jwt 都会出现“请输入所有字段错误”

React -- redux详解

fish_redux使用详解---看完就会用!