React-Redux 使用

2020-03-12  本文已影响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()方式来进行包装组件,这种方式就是我们在做 容器化组件展示组件 进行 分离的时候的 容器化组件

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

核心API

import TodoList from './list/TodoList';
import { Provider } from 'react-redux'
import store from './redux/store/index'
========================= 省略一大波代码 ======

// 重点这里
<Provider store={store}>
      <TodoList />
</Provider>, 

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

这个函数,就是监听 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 }
}

(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

这里例子使用了 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: 平常码云用的最多!

上一篇下一篇

猜你喜欢

热点阅读