(26)Redux 进阶——② Redux 中发送异步请求获取数据 | React 基础理论实操

7,805 阅读4分钟
转载请注明出处,未经同意,不可修改文章内容。

🔥🔥🔥“前端一万小时”两大明星专栏——“从零基础到轻松就业”、“前端面试刷题”,已于本月大改版,合二为一,干货满满,欢迎点击公众号菜单栏各模块了解。

涉及面试题:
如何发起 AJAX 调用以及应该在哪些组件生命周期方法中进行 AJAX 调用?

编号:[react_26]

1 获取接口的数据

紧接上篇代码,我希望发送一个 AJAX 请求,并将获取到的数据放到 TodoList 列表项里。
🔗前置知识:《React 进阶——⑧ React 生命周期函数(下):巧用 componentDidMount 进行 AJAX 数据请求》

打开 TodoList.js 文件(⚠️注意:我们依然用上边“前置知识”里 RAP2 模拟好的接口!)

import React, {Component} from "react";
import 'antd/dist/antd.css';
import store from "./store";
import {getInputChangeAction, getAddItemAction, getDeleteItemAction} from "./store/actionCreators"; 
import TodoListUI from "./TodoListUI"; 

import axios from "axios"; // 1️⃣首先,引入 axios 模块;

class TodoList extends Component {
  constructor(props) {
    super(props);
    
    this.state = store.getState();
    
    this.handleInputChange = this.handleInputChange.bind(this);  
    
    this.handleStoreChange = this.handleStoreChange.bind(this);  
    
    this.handleButtonClick = this.handleButtonClick.bind(this); 

    this.handleItemDelete = this.handleItemDelete.bind(this);
    
    store.subscribe(this.handleStoreChange);  
    
  }
  
  render() {
    return(
      <TodoListUI
        inputValue={this.state.inputValue}
        list={this.state.list}  
        handleInputChange={this.handleInputChange}
        handleButtonClick={this.handleButtonClick}
        handleItemDelete={this.handleItemDelete}
      />
    )
  }
  
  componentDidMount() { /*
  									    2️⃣然后在 componentDidMount 函数里,
                        去调用 axios 的相关方法获取数据;
                         */
    
    // 3️⃣调用 axios 的 get 方法,去获取模拟接口里的数据;
    axios.get("http://rap2api.taobao.org/app/mock/232799/api/todolist")  
    
    .then((res) => {  
    	const data = res.data.data; // 4️⃣一旦请求成功,就将 res.data.data 这个“数组”赋值给 data;
    })
    
    .catch(() => {alert("error")})
  } 
  
  handleInputChange(e) { 

    const action = getInputChangeAction(e.target.value)
    
    store.dispatch(action);  
  }

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


  handleButtonClick() { 
    
    const action = getAddItemAction();  
    
    store.dispatch(action); 
  }

  handleItemDelete(index) { 

    const action = getDeleteItemAction(index);
    
    store.dispatch(action); 
  } 

}

export default TodoList;

2 通过 Redux 的工作流程,运用接口返回的数据

5️⃣既然获取到了接口的数据,我们就可以按照 Redux 的工作流程进行一步步操作;

再次打开 TodoList.js 文件;

import React, {Component} from "react";
import 'antd/dist/antd.css';
import store from "./store";

// 5️⃣-③:引入 initListAction;
import {getInputChangeAction, getAddItemAction, getDeleteItemAction, initListAction} from "./store/actionCreators"; 

import TodoListUI from "./TodoListUI"; 

import axios from "axios";

class TodoList extends Component {
  constructor(props) {
    super(props);
    
    this.state = store.getState();
    
    this.handleInputChange = this.handleInputChange.bind(this);  
    
    this.handleStoreChange = this.handleStoreChange.bind(this);  
    
    this.handleButtonClick = this.handleButtonClick.bind(this); 

    this.handleItemDelete = this.handleItemDelete.bind(this);
    
    store.subscribe(this.handleStoreChange);  
    
  }
  
  render() {
    return(
      <TodoListUI
        inputValue={this.state.inputValue}
        list={this.state.list}  
        handleInputChange={this.handleInputChange}
        handleButtonClick={this.handleButtonClick}
        handleItemDelete={this.handleItemDelete}
      />
    )
  }
  
  componentDidMount() { 
    axios.get("http://rap2api.taobao.org/app/mock/232799/api/todolist")  
    
    .then((res) => {  
    	const data = res.data.data;  
      
      // 5️⃣-①:创建一个 action,让它表示我要做的事;
      const action = initListAction(data); /*
      																		 5️⃣-②:由于我们采用了 actionCreator 
      																		 统一创建 action 的方式编写代码,
                                           故这里直接调用 initListAction 函数,
                                           并将获得的“数据”作为“实参”传入;
                                           ❗️请一定记得在上边对 initListAction 引入!
                                            */
      
    })
    
    .catch(() => {alert("error")})
  } 
  
  handleInputChange(e) { 

    const action = getInputChangeAction(e.target.value)
    
    store.dispatch(action);  
  }

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


  handleButtonClick() { 
    
    const action = getAddItemAction();  
    
    store.dispatch(action); 
  }

  handleItemDelete(index) { 

    const action = getDeleteItemAction(index);
    
    store.dispatch(action); 
  } 

}

export default TodoList;

5️⃣-④:由于我们采用了 actionTypes 的拆分, 故需要在 actionTypes.js 中定义常量 INIT_LIST_ACTION

export const CHANGE_INPUT_VALUE = "change_input_value";
export const ADD_TODO_ITEM = "add_todo_item";
export const DELETE_TODO_ITEM = "delete_todo_item";

// ❗️定义常量 INIT_LIST_ACTION;
export const INIT_LIST_ACTION = "init_list_action";

打开 actionCreators.js 文件:

// 5️⃣-⑤:引入“常量”INIT_LIST_ACTION;
import {CHANGE_INPUT_VALUE, ADD_TODO_ITEM, DELETE_TODO_ITEM, INIT_LIST_ACTION} from "./actionTypes";  

export const getInputChangeAction = (value) => ({ 
  type: CHANGE_INPUT_VALUE, 
  value  
});

export const getAddItem = () => ({
  type: ADD_TODO_ITEM
});

export const getAddItemAction = () => ({
  type: ADD_TODO_ITEM
});

export const getDeleteItemAction = (index) => ({
  type: DELETE_TODO_ITEM,
  index
})

export const initListAction = (data) => ({ /*
																					 5️⃣-⑥:在 actionCreators.js 
                                           里创建一个 initListAction 函数,
                                           这个函数接收一个 data;
                                            */
  
  type: INIT_LIST_ACTION, /*
  												5️⃣-⑦:❗️❗️❗️在 React 里,action 需要用“对象”的形式来表示。
                          里边有一个 type 属性,用它来告诉 store“你要帮我做的事情是什么?”;
                           */
                          
  data // 5️⃣-⑧:将接收到的 data 返回;
})

5️⃣-⑨:在 TodoList.js 文件中,调用 store 的 dispatch 方法,将 action 发送给 store;

import React, {Component} from "react";
import 'antd/dist/antd.css';
import store from "./store";

import {getInputChangeAction, getAddItemAction, getDeleteItemAction, initListAction} from "./store/actionCreators"; 

import TodoListUI from "./TodoListUI"; 

import axios from "axios";

class TodoList extends Component {
  constructor(props) {
    super(props);
    
    this.state = store.getState();
    
    this.handleInputChange = this.handleInputChange.bind(this);  
    
    this.handleStoreChange = this.handleStoreChange.bind(this);  
    
    this.handleButtonClick = this.handleButtonClick.bind(this); 

    this.handleItemDelete = this.handleItemDelete.bind(this);
    
    store.subscribe(this.handleStoreChange);  
    
  }
  
  render() {
    return(
      <TodoListUI
        inputValue={this.state.inputValue}
        list={this.state.list}  
        handleInputChange={this.handleInputChange}
        handleButtonClick={this.handleButtonClick}
        handleItemDelete={this.handleItemDelete}
      />
    )
  }
  
  componentDidMount() { 
    axios.get("http://rap2api.taobao.org/app/mock/232799/api/todolist")  
    
    .then((res) => {  
      const data = res.data.data;  
      const action = initListAction(data);  
      
      store.dispatch(action); /*
      												❗️❗️❗️调用 store 的 dispatch 方法,
                              将 action 发送给 store;
                               */
    })
    
    .catch(() => {alert("error")})  
  } 
  
  handleInputChange(e) { 

    const action = getInputChangeAction(e.target.value)
    
    store.dispatch(action);  
  }

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


  handleButtonClick() { 
    
    const action = getAddItemAction();  
    
    store.dispatch(action); 
  }

  handleItemDelete(index) { 

    const action = getDeleteItemAction(index);
    
    store.dispatch(action); 
  } 

}

export default TodoList;

5️⃣-⑩:store 会自动地帮我们把 “当前 store 里的数据 previousState ”和“接收到的 action ” 转发给 reducer;

5️⃣-⑪:既然 reducer 拿到了 previousValueaction ,接下来 reducer 就需要告诉 store,现在你“新的数据”应该变成什么样子;

打开 reducer.js 文件:

// 5️⃣-⑫:引入常量 INIT_LIST_ACTION;
import {CHANGE_INPUT_VALUE, ADD_TODO_ITEM, DELETE_TODO_ITEM, INIT_LIST_ACTION} from "./actionTypes"; 

const defaultState = { 
  inputValue: "", 
  list: []
};

export default (state = defaultState, action) => { 
  
  if(action.type === CHANGE_INPUT_VALUE) {  
    
    const newState = JSON.parse(JSON.stringify(state)); 
  
    newState.inputValue = action.value;  
    
    return newState;  
  }
  
  if(action.type === INIT_LIST_ACTION) { /*
  																			 5️⃣-⑬:如果 action 的类型是 
  																			 INIT_LIST_ACTION,就执行下边的代码;
                                          */
    
    const newState = JSON.parse(JSON.stringify(state)); // 5️⃣-⑭:同理,拷贝一份数据;
  
    newState.list = action.data; // 5️⃣-⑮:使新数据里的 list 等于 action 的 data;
    
    return newState; // 5️⃣-⑯:同理,返回这个新数据。
  }  
  
  if(action.type === ADD_TODO_ITEM) { 
    
    const newState = JSON.parse(JSON.stringify(state)); 
    newState.list.push(newState.inputValue); 
    newState.inputValue = ""; 
    
    return newState; 
  }
  
  if(action.type === DELETE_TODO_ITEM) {  
    
    const newState = JSON.parse(JSON.stringify(state)); 
    
    newState.list.splice(action.index, 1);  

    return newState; 
  }
  
  return state;
}

返回页面查看(一切正常): react_26-01.gif

下一篇,我们会在本篇的基础上,通过使用 Redux 中的“中间件”来实现 AJAX 数据请求!

祝好,qdywxs ♥ you!