aiyoudiao aiyoudiao
  • JavaScript
  • Vue
  • React
  • 低代码
  • 线性系统
  • 暂未分类
  • LeetCode
  • 算法
  • 数据结构
  • 设计模式
  • Other
  • PMP
  • Office
  • 面试
  • Bash
  • 流年往事
  • 经验片段
  • 读书杂感
  • 归档
  • 分类
  • 标签
  • 简介
  • 收藏
  • 有趣
  • 文档

码二

扫微信二维码,认识一下码二吧😉。
  • JavaScript
  • Vue
  • React
  • 低代码
  • 线性系统
  • 暂未分类
  • LeetCode
  • 算法
  • 数据结构
  • 设计模式
  • Other
  • PMP
  • Office
  • 面试
  • Bash
  • 流年往事
  • 经验片段
  • 读书杂感
  • 归档
  • 分类
  • 标签
  • 简介
  • 收藏
  • 有趣
  • 文档
  • JavaScript

  • vue

  • react

    • 16_4

      • React16_4整理-开篇
      • React16_4整理-TodoList
      • React16_4整理-上阶
      • React16_4整理-Redux开篇
      • React16_4整理-Redux上阶
        • 前言
        • UI 组件与容器组件的拆分
          • 代理示例
        • React 中无状态组件
        • Redux 中发送异步请求获取数据
        • 使用 Redux-thunk 中间件进行 ajax 请求发送
        • 到底什么是 Redux 中间件?
          • 除了 redux-thunk 这样的中间件之外还有其它的中间件
        • Redux-sage 中间件的使用
        • React-redux
        • React-redux 的使用
        • 总结
      • React16_4整理-实战
    • react心得
    • react设计的哲学
    • react上手知识点(上篇)
    • react上手知识点(下篇)
    • antd
  • 低代码

  • 读书会

  • 线性代数

  • docker

  • auto

  • 杂记

  • 笔记
  • react
  • 16_4
aiyoudiao
2022-04-13

React16_4整理-Redux上阶

# 前言

前面说到React中 数据与视图分离,但是JS逻辑和视图是混在一起的,其实可以通过设计来进行拆分。
还有无状态组件以及React中redux的一些第三方插件,比如redux-thunk、redux-saga。
thunk推迟执行,saga用到了生成器,。这些第三方插件都是为了让状态管理更加的轻松,从而降低心智压力。

# UI 组件与容器组件的拆分

UI 组件也叫傻瓜组件,容器组件也叫聪明组件。
UI 组件负责页面的渲染,容器组件负责页面的逻辑。

# 代理示例

UI 组件-TodoListUI

import React,{ Component } from 'react';
import { Input ,Button, List } from 'antd';

import '../node_modules/antd/dist/antd.css';

class TodoListUI extends Component {
    render() {
        return(
            <div style = {{margin: '10px 0px 0px 10px',width: "500px"}}>
                <div>
                <Input placeholder = "请输入内容"
                value = {this.props.inputValue}
                onChange = {this.props.handleChange}
                style = {{marginRight: '10px',width: "350px"}}
                />
                <Button type = "primary"
                        style = {{width: "80px"}}
                        onClick = {this.props.handleClick}
                        >提交
                        </Button>
                <List
                    bordered
                    dataSource = {this.props.list}
                    style = {{width: '350px',marginTop: '10px'}}
                    renderItem = {(item, index) => (<List.Item onClick = {(index) => {
                        this.props.handleRemoveItem(index);
                    }}>{item}</List.Item>)}
                    />
                </div>
            </div>
        )
    }
}
export default TodoListUI;

容器组件-TodoList

import React,{ Component } from 'react';
import TodoListUI from './TodoListUI'

//import store from './store/index.js'
import store from './store';
// import {CHANGEINPUTVALUE,ADDLISTITEM,REMOVEITEM} from './store/actionTypes'
import {getInputeChangeAction, addListItemAction, removeItemAction} from './store/actionCreators';

class TodoList extends Component {
    constructor (props) {
        super(props);
        console.log(store.getState());
        this.state = store.getState();

        this.handleChange = this.handleChange.bind(this);
        this.handleStoreChange = this.handleStoreChange.bind(this);
        this.handleClick = this.handleClick.bind(this);
        this.handleRemoveItem = this.handleRemoveItem.bind(this);

        // 监听 store中的状态改变
        store.subscribe(this.handleStoreChange);
    }

    render () {
        return (
            <TodoListUI
                inputValue = {this.state.inputValue}
                handleChange = {this.handleChange}
                handleClick = {this.handleClick}
                handleRemoveItem = {this.handleRemoveItem}
            />
        )
    }

    handleChange (e) {
        const action = getInputeChangeAction(e.target.value)
        store.dispatch(action);
    }
    handleStoreChange () {
        this.setState(store.getState());
    }
    handleClick () {
        const action = addListItemAction();
        store.dispatch(action);
    }
    handleRemoveItem (index) {
        const action = removeItemAction(index);
        store.dispatch(action);
    }
}

export default TodoList;

# React 中无状态组件

以函数定义的方式定义一个组件,可以传递一个 props 来获取传递过来的数据。
当一个组件只有 render 函数的时候,这个时候就可以使用一个无状态的组件替换这个组件。

import React, { Component } from 'react';
import { Input, Button, List } from 'antd';

import '../node_modules/antd/dist/antd.css';
// 无状态组件的写法
const TodoListUI2 = (props) => {
    return(
        <div style = {{margin: '10px 0px 0px 10px',width: "500px"}}>
            <div>
            <Input placeholder = "请输入内容"
            value = {props.inputValue}
            onChange = {props.handleChange}
            style = {{marginRight: '10px', width: "350px"}}
            />
            <Button type = "primary"
                    style = {{width: "80px"}}
                    onClick = {props.handleClick}
                    >提交</Button>
            <List
                bordered
                dataSource = {props.list}
                style = {{width: '350px', marginTop: '10px'}}
                renderItem = {
                    (item,index) => (
                    <List.Item onClick = {() =>{
                        props.handleRemoveItem(index);
                    }}>{item}</List.Item>)
                }
                />
            </div>
        </div>
    )
}
export default TodoListUI2;

无状态的组件性能比较高,因为它本身就是一个函数。而有状态的组件继承自 React.Component,有一套生命周期,所以要去执行这一套生命周期,所以性能肯定没有只需要执行一个函数的组件好。
无状态组件一般用于 UI 组件中。

# Redux 中发送异步请求获取数据

在 ComponentDidMount 中发送 axios 异步请求,然后初始化状态。

# 使用 Redux-thunk 中间件进行 ajax 请求发送

首先安装 Redux-thunk
使用命令 yarn add redux-thunk 或者 npm install --save redux-thunk
引入 redux 的createStore、applyMiddleware、compose
然后再引入 redux-thunk ,最后创建store的时候将中转一下thunk后的enhancer作为第二个参数传递进去,之所以使用这种方式,是为了可以使用多个中间件。

import {createStore, applyMiddleware, compose} from 'redux';
import thunk from 'redux-thunk';
import reducer from '/reducer.js';
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION__ ? window.__REDUX_DEVTOOLS_EXTENSION__() : conpose;
// 做一个中转
const enhancer = composeEnhancers(
        applyMiddleware(...[thunk])
    )

const store=createStore(reducer, enhancer)
export default store;

使用redux-thunk,可以让store.dispatch中可以传递一个函数而不是仅仅只能是一个对象,所以说redux-thunk扩展了store.dispatch的功能,redux-thunx就是rudux的插件。

使用redux-thunk 之后,你使用store.dispatch,你如果传递一个函数进去,那么它会调用这个函数,并且把store.dispatch传递进去。
如果你传递的是一个对象,那么它会去调用reducer这个函数,也就是reducer.js导出的那个函数。
通过那个函数来进行state的处理和newState的返回,最后通过store改变state。

在使用redux创建store 的时候会使用到中间件,这是 redux 的中间件。

# 到底什么是 Redux 中间件?

就是对Redux中store的dispatch方法做了一个升级。
如redux-thunk对dispatch方法做了一个升级,默认的 dispatch只能传递一个对象,然后将这个对象和当前全局的state传递给reducer这个方法并调用,最后获取reducer方法中的返回值来修改state。
升级后的dispatch支持接收一个函数,这个函数会在dispatch方法体中被执行,并且会在执行的时候传递store.dispatch进去,直到你传递的是一个对象,之后就会像默认的dispatch那样,走完这套流程后最终修改state。

# 除了 redux-thunk 这样的中间件之外还有其它的中间件

如 redux-loger :用来记录每次 action 的日志
如 redux-saga:它也是解决Redux中异步问题的中间件,它不同于 redux-thunk 将异步请求放到 action 中进行,它是把异步操作单独的放到一个文件中进行管理

# Redux-sage 中间件的使用

Redux中间件指的是 action和store的中间,也就是dispatch这个函数,对它进行升级,只有redux中才有action和store的概念,将异步代码放到action中去做,有利于自动化测试,和代码的拆分管理。
使用命令安装 Redux-saga:npm install redux-saga --save或者yarn add redux-saga
使用Redux-saga:先从Redux-saga中引入 createSagaMiddleware执行createSagaMiddleware()之后传入 saga 中间件的的对象

import {createStore, applyMiddleware, compose} from 'redux';
import createSagaMiddleware from 'redux-saga';
import reducer from '/reducer.js';

const sagaMiddlware = createSagaMiddleware();
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION__ ? window.__REDUX_DEVTOOLS_EXTENSION__() : conpose;

// 做一个中转
const enhancer = composeEnhancers(
        applyMiddleware(...[sagaMiddlware])
)

const store = createStore(reducer, enhancer)
export default store;

compose 的使用: 你可以在里面传递很多的方法,传递的方法会依次被执行。

redux-saga 在处理非常大型项目时优于redux-thunk
redux-thunk没有什么 api,所以很简单,redux-saga有很多 api 所以相对复杂一点。

# React-redux

是 React 第三方模块儿,可以更加方便的使用redux。
使用命令来进行安装:yarn add react-redux。

react-redux 中提供的 API

Provider 组件

import { Provider } from 'react-redux';
import store from './store';
<!-- Provider表示提供器,store = store表示连接store,
    这样一来,里面的组件都可以直接使用连接的store了
-->
const App=(
    <Provider store = {store}>
        <TodoList />
    </Provider>
)

ReactDOM.render(App, document.getElementById("root"));

connect 方法

import {connect} from 'react-redux'
class TodoList extends Component {

}

// 这个函数表示将store中state映射到当前的props中去
const mapStateToPorps = (state) => {
    return {
        inputValue:state.inputValue
    }
}

// 表示将store.dispatch方法挂载到props中的函数成员中,
// 然后就可以直接在函数中调用dispatch了
const mapDispatchToProps = (dispatch) => {
    return {
        changeInputValue(e){
            const action = {
                type: 'changeInputValue',
                value: e.target.value
            }
            dispatch(action);
        }
    }
}

// connenct 表示连接Provider中的store
// mapStateToPorps 获取值 ,mapDispatchToProps 设置值,TodoList 被连接的组件

// 最终返回一个容器组件
export default connect(mapStateToPorps, mapDispatchToProps)(TodoList)

# React-redux 的使用

connect 方法返回的结果实际上是一个容器组件,因为它里面包含了 数据的传递和方法传递

import React, { Component } from 'react'
import {connect} from 'react-redux'
import {inputChange, clickSubmit, clickRemoveItem} from './store/actionCreators.js'

// 这是一个无状态的UI组件
const TodoList = (props) => {

    const {handleInputChange, handleClickSubmit, handleClickRemoveItem, list, inputValue} = props;
    return(
        <div>
            <input onChange = {handleInputChange.bind(this)} type = "text" value = {inputValue}/>
            <button onClick = {handleClickSubmit.bind(this)}>提交</button>
            <ul>
            {
                list.map((item, index) => {
                    return (
                        <li onClick = {handleClickRemoveItem.bind(this, index)} key = {index}>{item}</li>
                    )
                })
            }
            </ul>
        </div>
        )
}

// 将store.state映射到this.props中
const mapStateToPorps= (state) => {
                        return {
                            inputValue: state.inputValue,
                            list: state.list
                        }
                    }
// 将store.dispatch 传递到 所有的props里的自定义函数中
const mapDispatchToProps = (dispatch) => {
    return {
        handleInputChange (e) {
            const action = inputChange(e.target.value);
            dispatch(action);
        },
        handleClickSubmit () {
            const action = clickSubmit();
            dispatch(action);
        },
        handleClickRemoveItem (index) {
            const action = clickRemoveItem(index);
            dispatch(action);
        }
    }
}

// 这里返回一个容器组件
export default connect(mapStateToPorps, mapDispatchToProps)(TodoList)

# 总结

在redux中有很多状态管理的第三方插件(中间件),比如react-thunk、react-saga,这些中间件都是通过升级dispatch这个方法,来实现更加便捷更加优秀的状态管理机制。

react的react-redux更是加入了对redux的简易封装,更好的让你的代码组织方式更加优雅,从而提高开发效率,降低心智压力。

Provider表示提供器,store = store表示连接store,这样一来,里面的组件都可以直接使用连接的store。 connenct 表示连接Provider中的store

mapStateToPorps 从state中获取值,mapDispatchToProps 设置state值,TodoList 被连接的组件。
mapStateToPorps:这个函数表示将store中state映射到当前的props中去
mapDispatchToProps:表示将store.dispatch方法挂载到props中的函数成员中,然后就可以直接在函数中调用dispatch了。

#react#redux
上次更新时间: 10年18月2023日 01时57分53秒
React16_4整理-Redux开篇
React16_4整理-实战

← React16_4整理-Redux开篇 React16_4整理-实战 →

最近更新
01
01.数据结构导论一览.md
10-16
02
30.2023年06月04日.md
06-04
03
08.与测量相关.md
05-06
更多文章>
Theme by Vdoing | Copyright © 2017-2023 aiyoudiao 码二 备案号: 鄂ICP备2022002654号-1