React-Redux、redux-thunk基础知识

64 阅读3分钟

1.React-Redux基础用法

index.js

// import ReactDOM from 'react-dom'
import React from "react"
import App from "./App"
import { Provider } from "react-redux"
import store from "./store"
// ReactDOM.render(<App />, document.getElementById('root')) // before
import { createRoot } from 'react-dom/client'
const container = document.getElementById('root')
const root = createRoot(container) // createRoot(container!) if you use TypeScript
root.render(
    <Provider store={store}>
        <App tab="home" />
    </Provider>
)

store/index.js

import { createStore } from "redux"
import reducer from "./reducer"
const store = createStore(reducer)
export default store

action.js

import { ADD_COUNT } from "./constants"
export const addAction = (num) => {
    console.log('num', num)
    return {
        type: ADD_COUNT,
        num
    }
}

constants.js

export const ADD_COUNT = 'ADD_COUNT'

reducer.js

import { ADD_COUNT } from "./constants"
const initialState = {
    count: 1
}
const reducer = (state = initialState, action) => {
    switch (action.type) {
        case ADD_COUNT:
            return { count: state.count + action.num }
        default:
            return state
    }
}
export default reducer

about.js

import React from "react"
import { connect } from "react-redux"
// import connect from "../../store/connect/connect"
import { addAction } from '../../store/action'
class About extends React.PureComponent {
    render() {
        return (
            <div id={'about'}>
                About-----------
                <div>{this.props.count}</div>
                <button onClick={() => this.props.increment()}>++</button>
            </div>
        )
    }
}
const mapStateToProp = (state) => {
    return {
        count: state.count
    }
}
const mapStateToAction = (dispatch) => {
    return {
        increment() {
            dispatch(addAction(1))
        }
    }
}
export default connect(mapStateToProp, mapStateToAction)(About)

connect的实现原理

import React from "react"
import store from '../index'
function connect(mapStateToProp, mapStateToAction) {
    return function enhanceComponent(WrapComponent) {
        class AdvComponent extends React.PureComponent {
            constructor (props) {
                super(props)
                console.log('this/props', this.props)
                this.state = {
                    ...mapStateToProp(store.getState())
                }
            }
            componentDidMount() {
                store.subscribe(() => {
                    this.setState({
                        ...mapStateToProp(store.getState())
                    })
                })
            }
            render() {
                return (
                    <WrapComponent {...this.props} {...this.state} {...mapStateToAction(store.dispatch)}></WrapComponent>
                )
            }
        }
        return AdvComponent
    }

}
export default connect

redux-thunk

/*
使用redux-thunk之前:
                 --------------------
        ------>  | Component 异步请求 |  -----
       |         --------------------       |
       |                                    ↓
-------------       -------------       -------------
|   Store   | <---- |  Reducer  | <---- |  Action   |
-------------       -------------       -------------

使用redux-thunk之后:
                    -------------
        --------->  | Component |  ---------------------------------
       |            -------------                                   |
       |                                                            ↓
-------------       -------------       -------------       -------------
|   Store   | <---- |  Reducer  | <---- |  异步请求   | <---- |  Action   |
-------------       -------------       -------------       -------------
* */

安装

npm install redux-thunk

引用

store/index.js

import { createStore, applyMiddleware } from "redux"
import thunkMiddleware from "redux-thunk"
import reducer from "./reducer"
// 创建store之前,通过applyMiddleware方法,告诉Redux需要引用哪些中间件
const storeEnhancer = applyMiddleware(thunkMiddleware)
// 利用store来保存状态(state)
const store = createStore(reducer, storeEnhancer)
export default store

应用中间件

action.js

import { ADD_COUNT, CHANGE_ACTION } from "./constants"
export const addAction = (num) => {
    console.log('num', num)
    return {
        type: ADD_COUNT,
        num
    }
}
export const changeAction = (info) => {
    return {
        type: CHANGE_ACTION,
        info
    }
}
export const getInfo = (dispatch, getState) => { // 引用中间后提供的两个参数 dispatch, getState
    fetch('http://127.0.0.1:7001/info')
        .then((res) => {
            return res.json()
        })
        .then((data) => {
            dispatch(changeAction(data))
        })
        .catch(error => {
            console.log('error', error)
        })
}

constant.js

export const ADD_COUNT = 'ADD_COUNT'
export const CHANGE_ACTION = 'CHANGE_ACTION'

reducer.js

import { ADD_COUNT, CHANGE_ACTION } from "./constants"
const initialState = {
    count: 1,
    info: {}
}
const reducer = (state = initialState, action) => {
    switch (action.type) {
        case ADD_COUNT:
            return { ...state, count: state.count + action.num }
        case CHANGE_ACTION:
            return { ...state, info: action.info }
        default:
            return state
    }
}
export default reducer

...state: 将所有数据返回

About.js

import React from "react"
import { connect } from "react-redux"
// import connect from "../../store/connect/connect"
import { addAction, getInfo } from '../../store/action'

class About extends React.PureComponent {
    componentDidMount() {
        this.props.getInfo()
    }
    render() {
        return (
            <div id={'about'}>
                About-----------
                <div>{this.props.count}</div>
                <button onClick={() => this.props.increment()}>++</button>
                <div>{this.props.info.name}</div>
                <div>{this.props.info.age}</div>
            </div>
        )
    }
}
// 在mapStateToProps方法中告诉React-Redux, 需要将store中保存的哪些数据映射到当前组件的props上
const mapStateToProp = (state) => {
    return {
        count: state.count,
        info: state.info
    }
}
// 在mapDispatchToProps方法中告诉React-Redux, 需要将哪些派发的任务映射到当前组件的props上
const mapStateToAction = (dispatch) => {
    return {
        increment() {
            dispatch(addAction(1))
        },
        getInfo() {
            // redux-thunk中间件作用:
            // 可以让dispatch方法可以接收一个函数, 可以让我们在通过dispatch派发任务的时候去执行我们传入的方法
            dispatch(getInfo)
        }
    }
}
export default connect(mapStateToProp, mapStateToAction)(About)

redux-thunk的实现原理

const redux = require('redux');

// 定义一个状态
let initialState = {
    count: 0
};

// 利用store来保存状态(state)
const store = redux.createStore(reducer);

// 利用action来修改状态
const addAction = {type:'ADD_COUNT', num: 1};
const subAction = {type:'SUB_COUNT', num: 1};
const getUserInfo = (dispatch, getState)=>{
    setTimeout(()=>{
        console.log('获取到了异步数据');
        dispatch(addAction);
    }, 3000);
};

// 利用reducer将store和action串联起来
function reducer(state = initialState, action) {
    console.log('reducer被执行了');
    switch (action.type) {
        case 'ADD_COUNT':
            return {count: state.count + action.num};
        case 'SUB_COUNT':
            return {count: state.count - action.num};
        default:
            return state;
    }
}

// 在组件中如何修改Store中存储的状态?
/*
console.log('执行reducer之前做的事情');
store.dispatch(addAction);

console.log('执行reducer之前做的事情');
store.dispatch(subAction);
 */

/*
在redux-thunk中, 如果通过dispatch派发的任务是一个对象, 那么就立即执行reducer
                如果通过dispatch派发的任务是一个函数, 那么就执行这个函数
* */
/*
function thunkDispatch(action) {
    // console.log('执行reducer之前做的事情');
    // store.dispatch(action);
    if(typeof action === 'function'){
        action(store.dispatch, store.getState);
    }else{
        store.dispatch(action);
    }
}

// thunkDispatch(addAction);
thunkDispatch(getUserInfo);
 */
function thunkDispath(store) {
    const storeDispath = store.dispatch;
    const storeGetState = store.getState;

    function myDispatch(action) {
        if(typeof action === 'function'){
            action(storeDispath, storeGetState);
        }else{
            storeDispath(action);
        }
    }
    // 将官方的dispatch函数修改为我们自定义的dispatch函数
    store.dispatch = myDispatch;
}

thunkDispath(store);

// 调用的实际是我们自定义的dispatch函数
// store.dispatch(addAction);
store.dispatch(getUserInfo);
  • 根据判断action返回的对象还是函数来做处理
  • 如果是对象直接执行
  • 如果是函数,参数传入两个参数dispatch、getState