美文网首页
React-Redux 使用

React-Redux 使用

作者: 爱吃豆包 | 来源:发表于2020-03-12 23:37 被阅读0次

    目前使用版本

    "redux": "^4.0.5"
    "react-redux": "^7.2.0",
    

    建议先了解 Redux 的使用!Redux使用(纯Redux使用)

    React-Redux 是 Redux 和 React 的绑定库!

    为什么要使用这个 React-Redux 库:

    在之前的文章Redux使用(纯Redux使用)里面使用的是 store.subscribe()的方式进行监听了store 的里面的state的变化!虽说这样做也可以,但是会有其他的性能问题,比如:渲染页面重复的问题,你可能通过生命周期函数shouldComponentUpdate可以处理,但是这样太繁琐,特别是组件越来越复杂之后!
    React-Redux 这个库在官方说明中是有性能优化的!特别是提供了一种connect()方式来进行包装组件,这种方式就是我们在做 容器化组件展示组件 进行 分离的时候的 容器化组件

    • 容器组件:处理 props 或者 state
    • 展示组件:只负责展示界面

    比如说:你把网路请求放到 容器组件 中,然后在 容器组件 里面把数据组装好,然后传递给 展示组件 直接渲染页面展示!
    可以看看我之前的文章:React高阶组件

    核心API

    • <Provider store={store}>...</Provider>:这个组件是重点,要在你的根目录下的index.js文件把根组件进行包裹
    import TodoList from './list/TodoList';
    import { Provider } from 'react-redux'
    import store from './redux/store/index'
    ========================= 省略一大波代码 ======
    
    // 重点这里
    <Provider store={store}>
          <TodoList />
    </Provider>, 
    
    • connect(....) :连接函数,把组件和redux进行关联!这个是重点函数,这里可以把 statedispatch 传递进去!

    connect(....) 有几个参数很关键(重点关注两个):

    • mapStateToProps(state, [ownProps]):如果定义该参数,组件将会监听 Redux store 的变化。任何时候,只要 Redux store 发生改变,mapStateToProps 函数就会被调用。该回调函数必须返回一个纯对象,这个对象会与组件的 props 合并!

    这个函数,就是监听 Redux store 的数据变化的!!

    /**
     * 把 store 里面 state 状态,附加到 props 上
     * 这里的参数两个参数,connect()自动赋值
     * @param {*} state store的全局状态,connect()自动赋值
     * @param {*} ownProps 组件本身自己带的props, connect()自动赋值
     */
    const mapStateToProps = (state, ownProps) => {
    
        /**
         * 这里可以只拿取你需要的 state 里面的数据,这样可以节省性能开销
         * 比如我这里只要 state 里面的 list
         * 然后组件里面可以通过 props 获取 list 的值
         */
    
        return { list: state.list }
    }
    
    • mapDispatchToProps(dispatch, [ownProps]):如果传递的是一个对象,那么每个定义在该对象的函数都将被当作 Redux action creator,对象所定义的方法名将作为属性名;每个方法将返回一个新的函数,函数中dispatch方法会将 action creator 的返回值作为参数执行。这些属性会被合并到组件的 props 中。

    (1):这个函数,就是用来执行dispatch的,就是说可以把这个组件中所有的dispatch操作从组件里面都提取出来统一管理!
    (2):如果不定义 mapDispatchToProps ,那么默认把所有的dispatch都传递到组件中,那么你可以在组件中直接操作dispatch

    /**
     * 把里面定义的函数附加到 props 上
     * 组件可以通过 props.onTodoClick(id) 进行调用
     */
    const mapDispatchToProps = (dispatch, ownProps) => {
      return {
        /**
         * 可以定义多个函数
         * 组件可以通过 props.onTodoClick(id) 进行调用
         **/
        onTodoClick: id => {
          dispatch(toggleTodo(id))
        }
      }
    }
    

    开始使用 React-Redux

    安装依赖

    // redux 相关
    yarn add redux react-redux redux-devtools-extension --save
    

    这里安装了三个库:reduxreact-reduxredux-devtools-extension

    • redux 是 Redux 的原生核心库
    • react-redux 是 React 和 Redux 的绑定库(有额外的性能优化)
    • redux-devtools-extension 是一个开发组工具库可以在浏览器上看到 store 里面的 state 的变化,方便调试!

    这里例子使用了 Antd 组件库!

    先定义 action

    // redux/action/list/index.js
    
    /**
     * Action 类型
     *      事件类型
     */
    export const type = {
        ADD_LIST: 'ADD_LIST'
    }
    
    /**
     * 添加 List
     * @description 也就是获取添加 List 操作类型, 以及携带的数据
     * @param {*} data 携带的数据
     */
    export function addList(data) {
        return {
            type: type.ADD_LIST,
            data
        }
    }
    

    定义 reducer

    // redux/reducer/list/index.js
    
    import { type } from '../../action/list'
    
     // 数据仓库
     const initialState = {
        data: [
            "这是第一行",
            "这是第二行",
            "这是第三行"
        ],
     }
    
     /**
      *  list 数据处理
      * @param {*} state 
      * @param {*} action 
      */
    export default function list(state = initialState, action) {
        switch (action.type) {
            case type.ADD_LIST:
    
                /**
                 * 处理完一些里操作后,返回一个新的 state
                 */
    
                // 把新的值,添加进 state
                const newData = state.data.concat(action.data)
    
                return {
                    ...state,
                    data: newData
                }
            default:
                return { ...state }
        }
    }
    
    

    集中我们定义了一系列的 reducer 的函数

    // redux/reducer/index.js
    
    /**
     * Reducer 数据处理
     */
    import { combineReducers } from 'redux'
    import list from './list'
    
    /**
     * 把多个 reducer 进行合并成一个
     */
    export default combineReducers({
    
        /**
         * 写入一系列的 reducer
         */
    
        list
    })
    

    创建 store

    /**
     * 创建数据源  store
     */
    import { createStore } from 'redux'
    import reducer from '../reducer'
    import { composeWithDevTools }  from 'redux-devtools-extension'
    
    // 创建 store
    // reducer 一定要是一个函数
    // composeWithDevTools() 一定要写成这样,不能写成 composeWithDevTools
    const store = createStore(reducer, composeWithDevTools())
    export default store
    
    

    创建 TodoList.js

    import React, { Component } from 'react'
    import { Input, Button, List } from 'antd';
    import { connect } from 'react-redux'
    import { addList } from '../redux/action/list'
    
    /**
     * TodoList 一个列表
     */
    class TodoList extends Component {
    
        constructor(props) {
            super(props)
            
            this.inpVal = React.createRef();
    
            this.state = {
                // data: [
                //     "这是第一行",
                //     "这是第二行",
                //     "这是第三行"
                // ],
                data: []
            }
    
        }
    
        componentDidMount() {
            this.setState({ data: this.props.list.data || [] })
        }
    
        componentDidUpdate(prevProps) {
            // 典型用法(不要忘记比较 props)
            if (this.props.list.data !== prevProps.list.data) {
                this.setState({ data: this.props.list.data || [] })
            }
        }
    
        addData() {
            const { dispatch } = this.props
            const inputValue = this.inpVal.current.state.value
            console.log('当前值:', inputValue)
            if (inputValue === undefined) {
                return
            }
            // this.setState({ data: this.state.data.concat(inputValue) })
            // 更新store
            dispatch(addList(inputValue))
            this.inpVal.current.state.value = undefined
        }
    
        render() {
            // console.log('this.props: ', this.props)
            return (
                <>
                    <div style={{ margin: '10px' }}>
                        <div>
                            <Input ref={ this.inpVal } placeholder="请输入内容" style={{ width: '200px' }}/>
                            <Button type="primary" style={{ marginLeft: '10px' }} onClick={this.addData.bind(this)}>确认</Button>
                            <List
                                style={{ marginTop: '10px', width: '200px' }}
                                bordered
                                dataSource={this.state.data}
                                renderItem={(item, index) => (
                                    <List.Item key={index}>
                                        {item}
                                    </List.Item>
                                )}
                            />
                        </div>
                    </div>
                </>
            )
        }
    }
    
    /**
     * 把 store 里面 state 状态,附加到 props 上
     * @param {*} state store的全局状态
     * @param {*} ownProps 组件本身自己带的props
     */
    const mapStateToProps = (state, ownProps) => {
    
        /**
         * 这里可以只拿取你需要的 state 里面的数据,这样可以节省性能开销
         * 比如我这里只要 state 里面的 list
         * 然后组件里面可以通过 props 获取 list 的值
         */
    
        return { list: state.list }
    }
    
    /**
     * connect 是一个容器
     * 把 原有的组件进行装饰一下(装饰者模式)
     */
    export default connect(mapStateToProps)(TodoList)
    
    
    

    修改根目录下 index.js 文件

    import React from 'react';
    import ReactDOM from 'react-dom';
    import './index.css';
    import TodoList from './list/TodoList';
    import { Provider } from 'react-redux'
    import store from './redux/store/index'
    import * as serviceWorker from './serviceWorker';
    
    ReactDOM.render(
        <Provider store={store}>
            <TodoList />
        </Provider>, 
        document.getElementById('root')
    );
    
    // If you want your app to work offline and load faster, you can change
    // unregister() to register() below. Note this comes with some pitfalls.
    // Learn more about service workers: https://bit.ly/CRA-PWA
    serviceWorker.unregister();
    

    结果:

    结果截图

    题外话:

    结合实际项目开发的时候,redux 肯定是分为多个子模块的。可以把 actionreducer 拆分成多个!那么 reducer 拆分后,在定义一个统一的 reducer 文件进行合并!通过 redux 提供的 combineReducers 函数可以把多个子reducer进行合并!

    示例图

    代码:https://github.com/weiximei/redux-demo
    ps: 平常码云用的最多!

    相关文章

      网友评论

          本文标题:React-Redux 使用

          本文链接:https://www.haomeiwen.com/subject/wwsgjhtx.html