Skip to content

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

什么是Redux中间件

  • 中间件:程序执行过程中,加入的附件,用来处理数据、流程、对象等操作。
  • Redux中间件指的是Action与Store之间。之前,在Redux中Action只能是一个对象,Action以对象的形式直接派发给了Store,但是现在我们使用了Redux-thunk之后,Action可以是函数了。变成函数的原因如下图,Action通过dispatch方法传递给了Store,因此dispatch就是Action和Store中间的部分,实际上该中间件就是对dispatch的封装和升级。当没有中间件时,是dispatch接收到一个Action的对象把对象传递给Stroe。当有了中间件时,如果Action传输的是一个函数的话,会先将函数执行将函数结果转换成对象传输给Store。
    Image title
    Redux的标准流程:View在Redux中会派发一个Action,Action通过Store的dispatch方法会派发给Store,Store接收到Action连同之前的state一起传给Reducer,Reducer返回一个新的数据给Store,Store去改变自己的state。

安装

使用

  • 使用了redux-thunk后在action部分不仅可以返回函数,还可以返回对象。
1
2
3
4
5
import { createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
import rootReducer from './reducers/index'

const store = createStore(rootReducer, applyMiddleware(thunk))

代码示例

import React, { Component } from "react";
import store from "./store";
import { getTodoList } from "./store/actionCreators";
import TodoListUI from './TodoListUI';

class TodoList extends Component {

    // 构造方法,固定接收props
    constructor(props) {
        // 当props发生改变,render就会被重新执行
        // 当父组件的render函数被运行时,它的子组件的render都将被重新运行
        // 调用父类的构造函数
        super(props);
        this.state = store.getState()
        this.handleInputChange = this.handleInputChange.bind(this)
        this.handleStoreChange = this.handleStoreChange.bind(this)
        this.handleBtnClick = this.handleBtnClick.bind(this)
        this.handleItemDelete = this.handleItemDelete.bind(this)
        // 自动订阅store,监听store的内容
        store.subscribe(this.handleStoreChange);
    }

    render() {
        return <TodoListUI
            inputValue={this.state.inputValue}
            handleInputChange={this.handleInputChange}
            handleBtnClick={this.handleBtnClick}
            list={this.state.list}
            handleItemDelete={this.handleItemDelete}
        />
    }

    componentDidMount () {
        const action = getTodoList();
        /*
        console.log('action', action)
        action () => {
            axios__WEBPACK_IMPORTED_MODULE_1__["default"].get('http://e.com/api/index/index').then(res => {
                const data = res.data;
                console.log(data);
                // const action = initListActio…
        */
        store.dispatch(action);
    }

    handleInputChange(e) {
        const value = e.target.value;
        const action = {
            type: 'change_input_value',
            value: value
        }
        store.dispatch(action);
    }

    handleStoreChange () {
        this.setState(store.getState())
    }

    handleBtnClick() {
        const value = this.state.inputValue
        const action = {
            type: 'change_child_value',
            value: value
        }
        store.dispatch(action);
    }

    handleItemDelete(index) {
        const action = {
            type: 'del_child_value',
            index: index
        }
        console.log(action)
        store.dispatch(action)
    }
}

export default TodoList
import axios from 'axios';
import { INIT_LIST_ACTION } from './actionTypes';

export const initListAction = (data) => ({
    type: INIT_LIST_ACTION,
    data
})

export const getTodoList = () => {
    return (dispatch) => {
        axios.get('http://e.com/api/index/index')
            .then((res) => {
                const data = res.data;
                const action = initListAction(data);
                dispatch(action);
            })
            .catch(() => {
                alert('error')
            })
    }
}
import React, { Component, Fragment } from "react";
import TodoItem from "./TodoItem";
import './style.css'

class TodoListUI extends Component {
    render () {
        return (
            <Fragment>
                <div>
                    <label htmlFor="insertArea">输入内容</label>
                    <input
                        id="insertArea"
                        className="input"
                        value={this.props.inputValue}
                        onChange={this.props.handleInputChange}
                    />
                    <button onClick={this.props.handleBtnClick}>提交</button>
                </div>
                <ul>
                    {
                        // 渲染数据
                        this.props.list.map((item, index) => {
                            return (
                                <TodoItem
                                    itemVal={item}
                                    index={index}
                                    del={this.props.handleItemDelete}
                                />
                            )
                        })
                    }
                </ul>
            </Fragment>
        )
    }
}

export default TodoListUI;
// 定义在reducer只有两个字段,后续传入到store store也就知道reducer存储内容的结构了
const defaultState = {
    inputValue: '',
    list: [],
    index: '',
}
// state = defaultState 默认什么都不存储
// reducer 可以接收state,但是绝不能修改state
export default (state = defaultState, action) => {
    // console.log(state, action)
    /*
    {inputValue: '', list: Array(0)}]:
    {type: 'change_input_value', value: 'f'}
    */
    if (action.type === 'change_input_value') {
        // 执行一次深拷贝 然后修改深拷贝的值
        const newState = JSON.parse(JSON.stringify(state));
        newState.inputValue = action.value;
        return newState;  
    }
    if (action.type === 'change_child_value') {
        const newState = JSON.parse(JSON.stringify(state));
        newState.list.push(newState.inputValue);
        newState.inputValue = '';
        console.log('change_child_value:newState', newState)
        /**
        {
            inputValue: ""
            list: ['123', '321']
        }
        */
        return newState;
    }
    if (action.type === 'del_child_value') {
        const newState = JSON.parse(JSON.stringify(state))
        console.log(newState)
        // console.log(newState, state)
        newState.list.splice(action.index, 1);
        return newState;
    }
    if (action.type === 'init_list_action') {
        const newState = JSON.parse(JSON.stringify(state))
        newState.list = action.data;
        return newState;
    }
    // state: 整个store存储的数据
    return state
}