Redux & React-Redux必知必会

Redux 使用

为什么要在React中使用Redux?

我们知道,react的核心是组件,而组件中有两个重要的属性:

  • props,父子组件通信的桥梁
  • state,组件内部的状态管理,仅组件内部可访问和修改。

React没有数据回溯的能力,主张单向数据流,所以很多时候,我们发现无法让两个组件进行通信(或者说共享状态),而通过层级传递的方法有比较难以接受。所以,我们需要一种机制,能把所有的state集中到组件顶部,能够灵活的将所有state各取所需的分发给所有的组件,这就是Redux。

Redux工作原理

正如上面的图片展示一样,redux的数据流是单向的。

我们将状态统一存储在store里面,而我们可以改变state的唯一方法就是去派发(dispatch)一个方法(action),这个action会被相应的reducer进行处理,返回新的state。

那么我们的组件如何知道state更新了呢?

我们可以使用订阅(subscribe)的形式,来刷新视图,当dispatch一个action导致状态更新时,自动去发布通知,执行render。

Reducer是啥?

reducer是一个纯函数,接受旧的state和action,返回新的state。保持它的纯净很关键,永远不要在里面做类似如下的操作:

  • 修改入参
  • 副作用操作,如异步请求,路由跳转
  • 调用非纯函数,如 Math.random(),new Date

下面来看下具体的使用

Redux基本使用

  1. 安装redux
npm i redux -S
  1. 创建store
import { createStore } from 'redux'

 // reducer 创建
function counterReducer(state = 0, action) {
    console.log(state) // 可以查看状态的变更
    switch (action.type) {
        case 'ADD':
            return state + 1
            break;
        case 'minus':
            return state - 1
        default:
            return state
            break;
    }
}

const store = createStore(counterReducer)

export default store

  1. 引入,获取状态,操作
// 1. 引入
import store from '../store/reduxStore'

class ReduxPage extends Component {
    state = {}
    // 3. 状态变更
    add = () =>{
        store.dispatch({type:'ADD'})
    }
    render() {
        return (
            <div>
                // 2. 状态获取
                <p>{store.getState()}</p>
                <button onClick={this.add}>计数</button>
            </div>
        );
    }
}

我们可以在页面中打印store,发现它是一个对象,包括几个方法,其中就有getState、dispatch、subscribe等方法。

此时,在页面点击按钮进行计数加一,控制台中我们发现状态变了,但是页面内容没有发生变化,这是因为我们变更了state,但是没有通知页面刷新。
4. 订阅变更

页面没有显示最新的count,主要是因为页面没有重新render,所以我们可以有一下几种方式来实现页面的强制刷新

  • dispatch后,手动this.setState({})
  • this.forceUpdate()
  • 订阅通知

前两种应该很熟悉了,我们来实现最后一种

// 入口文件 index.js
import store from './store/reduxStore'

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

总结

  1. createStore 创建store
  2. reducer 初始化、修改状态函数
  3. getState 获取状态值
  4. dispatch 提交更新
  5. subscribe 变更订阅

下篇文章,我们手动实现一个简单的Redux,现在先来看下React-Redux,它使我们能够更好的使用redux。

React-Redux使用

安装

npm i react-redux -S

react-redux基本使用

  1. 创建store,跟上面的栗子一致
  2. 引入,并在顶层导入
// 入口index.js
import { Provider } from 'react-redux'

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

内部原理实际上是使用了Context.Provider

  1. 在组件中使用
//1. 导入辅助函数connect
import { connect } from 'react-redux'

class ReactReduxPage extends Component {
    state = {}
    render() {
        // 3. 直接从props中拿到想要的状态和函数
        const { count, add, minus } = this.props
        return (
            <div>
                <p>{count}</p>
                <button onClick={add}></button>
                <button onClick={minus}></button>
            </div>
        );
    }
}

// 2. connect接受当前组件,将store映射到组件的props
export default connect(
    //mapStateToProps
    state => ({ count: state }),
    //mapDispatchToProps
    {
        add: () => ({ type: 'ADD' }),
        minus: () => ({ type: 'MINUS' })
    }
)(ReactReduxPage);

connect返回一个HOC,接受当前组件,返回一个组件,它里面的实际工作是接受两个参数,第一个是mapStateToProps,定义了将状态映射为props的规则,另一个mapDispatchToProps定义了将action映射为具体props中函数的规则,它可以是一个对象或函数。

Redux中的异步

Redux只是个纯粹的状态管理器,默认只⽀持同步,实现异步任务
⽐如延迟,⽹络请求,需要中间件的⽀持。

redux-thunk是可以用来处理异步操作的一个中间件。

现在加入我们不用redux,我们来模拟一个异步的操作,添加一个延迟一秒后新增计数的按钮。

 <button onClick={this.asyncAdd}>异步加</button>

我们会定义一个函数,然后异步结束后手动调用dispatch,像这样:

asyncAdd =()=>{
    setTimeout(()=>{
        store.dispatch({type:"ADD"})
    },1000)
}

现在我们看下redux-thunk是如何更好的解决的。

Redux-thunk

  1. 安装redux-thunk
npm i redux-thunk -S
  1. 加载中间件
import { counterReducer } from '../reducer/counterReducer'
import { createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
import logger from 'redux-logger'

const store = createStore(counterReducer, applyMiddleware(logger, thunk))

export default store

我们使用中间件的形式,对redux的dispatch进行了增强,可以处理异步操作,其实是对action进行了拦截处理,最后将执行权交还给redux
3. 异步action 返回一个函数,不是对象

// 将action抽离为单独的文件
export const add = () =>({type:'ADD'})

export const minus = () =>({type:'MINUS'})

// 异步action,最终返回的不是一个对象,而是一个函数,以dispatch入参,执行完异步操作后,载进行redux的dispatch
export const asyncAdd = payload => {
    return dispatch => {
        setTimeout(() => {
            dispatch({ type: 'ADD' })
        }, 1000)
    }
}

thunk会拦截action,对普通的同步action放行,对异步函数式的action,直接执行函数。
5. 引入,操作

import React, { Component } from 'react'
import { connect } from 'react-redux'
// 1. 将action抽离为单独的文件
import { add, minus, asyncAdd } from '../action/counterAction'

class ReactReduxPage extends Component {
    state = {}
    render() {
        // 3. 这里不变
        const { count, add, minus, asyncAdd } = this.props
        return (
            <div>
                <p>{count}</p>
                <button onClick={add}></button>
                <button onClick={asyncAdd}>异步加</button>
                <button onClick={minus}></button>
            </div>
        );
    }
}

export default connect(
    state => ({ count: state }),
    //2. 进行映射
    {
        add,
        minus,
        asyncAdd
    }
)(ReactReduxPage);

下一篇:手写 Redux & React-Redux

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值