React之React-Redux

在这里插入图片描述

实际项目中,需要权衡是直接使用 Redux 还是用 React-Redux

关于Redux

React 之 React 详解传送门

Redux 与 React-Redux 区别

redux比较,React-redux更为简洁,只要在mapStateToProps中绑定的state或者action就直接可以在组件的props中获取到,这样stateactionmapStateToProps统一管理,使用起来很方便。

更重要的是,React-Redux自己会监听state的变化进行更新,而redux需要手动的在生命周期componentDidMount中通过store.subscribe()来订阅事件 更新state


关于UI 组件与容器组件

React-Redux将所有组件分成两大类:UI 组件容器组件

UI 组件

  • 只负责 UI 的呈现,不带有任何业务逻辑
  • 没有状态(即不使用this.state这个变量)
  • 所有数据都由参数(this.props)提供
  • 不使用任何 Redux 的 API

容器组件

  • 负责管理数据和业务逻辑,不负责 UI 的呈现
  • 带有内部状态
  • 使用 Redux 的 API

UI 组件负责 UI 的呈现,容器组件负责管理数据和逻辑。

如果一个组件既有 UI 又有业务逻辑,那怎么办?
回答是,将它拆分成下面的结构:外面是一个容器组件,里面包了一个UI 组件。
前者负责与外部的通信,将数据传给后者,由后者渲染出视图。

React-Redux 规定,所有的 UI 组件都由用户提供,容器组件则是由 React-Redux 自动生成。
也就是说,用户负责视觉层,状态管理则是全部交给它。


安装React-Redux

npm install react-redux --save

yarn add react-redux


使用React-Redux

1. Provider组件

React-Redux 提供Provider组件,Provider 包裹在根组件外层,使所有的子组件都可以拿到 state

  1. Provider连接了store
  2. Provider内部的所有组件都可以使用store

src/index.js 中引入Provider:

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { Provider } from 'react-redux'; // 引入Provider
import store from './redux/store'; // 引入store

ReactDOM.render(
    <React.StrictMode>
        {/* 使用Provider并加载数据仓库 */}
        <Provider store={store}> 
            <App />
        </Provider>
    </React.StrictMode>,
    document.getElementById('root')
);

.

2. connect

React-Redux 提供connect方法,用于从 UI 组件生成容器组件。connect的意思,就是将这两种组件连起来

import { connect } from 'react-redux'
// ...
export const VisibleList = connect()(List); 

ListUI 组件VisibleList 就是由 React-Redux 通过 connect 方法自动生成的容器组件

.

3. mapStateToProps和mapDispatchToProps

connect方法接受两个参数:mapStateToPropsmapDispatchToProps。它们定义了 UI 组件的业务逻辑。

3.1 mapStateToProps()

负责输入逻辑,即将state映射到 UI 组件的参数(props)

mapStateToProps()是一个函数,建立一个从(外部的)state对象到(UI 组件的)props对象的映射关系
该函数返回一个对象,里面的每一个键值对就是一个映射。

每当state更新的时候,就会自动执行,重新计算 UI 组件的参数,从而触发 UI 组件的重新渲染。

// state就是数据仓库store的数据
const mapStateToProps = state => {
    return {
        myValue: state.myValue
    };
};

state数据映射到props中,这样在 jsx 中就可以this.props.myValue来代替this.state.myValue获取值

因此就不需要在构造函数中初始化state,也无需订阅store:

constructor(props) {
    super(props);

	// 因此就不需要在构造函数中初始化这个state
    // const storeState = store.getState();
    // this.state = {
    //     myValue: storeState.myValue
    // }
    
    // 也无需订阅store
    // store.subscribe(this.storeChange.bind(this));
}

3.2 mapDispatchToProps()

负责输出逻辑,即将用户对 UI 组件的操作映射成 Action

mapDispatchToProps()作为函数,返回一个对象,该对象的每个键值对都是一个映射,定义了 UI 组件的参数怎样发出 Action。

用来建立 UI 组件的参数到store.dispatch方法的映射。也就是说,它定义了哪些用户的操作应该当作 Action,传给 Store。

const mapDispatchToProps = dispatch => {
    return {
        changeInput: (e) => {
            const action = {
                type: 'change_input',
                value: e.target.value,
            };
            dispatch(action); // 分发action
        },
        // ...
    };
};

store.dispatch()挂载到props上,这样在 jsx 中就可以this.props.changeInput来代替store.dispatch()改变store里的数据

// changeInput = (e) => {
//     const action = {
//         type: 'change_input',
//         value: e.target.value,
//     };
//     store.dispatch(action);   // 用 this.props.changeInput 来代替 store.dispatch() 改变 store 里的数据
// }

3.3 connect(mapStateToProps, mapDispatchToProps)

connect方法接受mapStateToPropsmapDispatchToProps

export const VisibleList = connect(mapStateToProps, mapDispatchToProps)(List); 

简单的例子

将上面几个部分整合一下:

src/List.js

import { Component } from 'react';
import { connect } from 'react-redux';

class List extends Component {
    render() {
        return (
	        <div>
	            <label htmlFor="input">输入内容</label>
	            <input id="input" type="text" value={this.props.myValue} onChange={this.props.changeInput} />
	        </div>
        );
    }
}

// 把state数据映射到props中
// 这样在jsx中就可以用this.props.myValue来代替this.state.myValue获取值
const mapStateToProps = state => {
    return {
        myValue: state.myValue,
    };
};

// 把store.dispatch()挂载到props上
// 这样在jsx中就可以用this.props.changeInput来代替store.dispatch()改变store里的数据
const mapDispatchToProps = dispatch => {
    return {
        changeInput(e){
            const action = {
                type: 'change_input',
                value: e.target.value,
            };
            dispatch(action);
        }
    };
};

// List是 UI 组件,VisibleList 就是由 React-Redux 通过connect方法自动生成的容器组件。
export const VisibleList = connect(mapStateToProps, mapDispatchToProps)(List); 

注:以上类组件中的connect(mapStateToProps, mapDispatchToProps)使用较为繁琐,可以使用函数式组件中的hooks来替代,传送门

src/store/reducer.js

const defaultState = {
    myValue: ''
};

const reducer = (state = defaultState, action) => {
    switch (action.type) {
        case 'change_input':
            return { ...state, myValue: action.value }; // 不能直接修改旧的state,而是返回一个新的state来替代
        default:
            return state;
    }
};

export default reducer;

src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { Provider } from 'react-redux'; // 引入Provider
import store from './redux/store'; // 引入store

ReactDOM.render(
    <React.StrictMode>
        {/* 使用Provider并加载数据仓库 */}
        <Provider store={store}> 
            <App />
        </Provider>
    </React.StrictMode>,
    document.getElementById('root')
);

很重要,一定要掌握
end~

posted @ 2022-04-26 17:49  猫老板的豆  阅读(105)  评论(0编辑  收藏  举报