(18)React 进阶——⑧ React 生命周期函数(下):巧用 componentDidMount 进行 AJAX 数据请求 | React 基础理论实操

转载请注明出处,未经同意,不可修改文章内容。

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

javascript 复制代码
涉及面试题:
如何在重新加载页面时保留数据?

编号:[react_18]

1 React 中发 AJAX 请求应该放在哪个"生命周期函数"里

❓紧接上一篇的代码,我们有一个新的需求:

我希望通过 AJAX 从一个"接口上"请求一个远程的数据(远程数据里边包含了 TodoList 的一些内容),然后把请求到的"远程数据"加载到本地,并显示在页面上的"列表项"里。

答:

🔗前置知识:《React 进阶------⑥ React 生命周期函数(上):弄懂所有"生命周期函数"》

《发出请求的"客户端":② 浏览器异步发送"HTTP 数据请求"------初识 AJAX》

《发出请求的"客户端":③ 浏览器异步发送"HTTP 数据请求"------XMLHttpRequest 对象详解》

1️⃣在 React 中,我们想发一个 AJAX 请求该怎么做呢?或者说,发 AJAX 请求相关的代码应该放在 TodoList.js 文件的哪个地方呢?

前端界到目前为止依然有讨论这个问题的声音。一个比较公认的,且不会报错的做法是:将 AJAX 请求相关的代码,放在"生命周期函数" componentDidMount 里。

因为在本页面上,AJAX 获取数据只需要获取一次。我们自然而然地就考虑到,React 的"生命周期函数"里,是否也有只执行一次的函数。

之前的文章我们讲过,所有"生命周期函数"里,只有两个函数只执行一次: componentWillMountcomponentDidMount

  • componentWillMount :放在这个函数里,理论上是没有任何问题的。但,当我们去写 React Native 或用 React 去做"服务器端渲染"等更深层次技术的时候,如果把 AJAX 获取数据相关的代码放在这个函数里,会产生一些"冲突";

  • componentDidMount :实际工作中,我们约定是把 AJAX 获取数据相关的代码放在这个函数里。

(💡当然,还有的声音说,把 AJAX 获取数据相关的代码放在 constructor 里。从理论上来说,也是可以的,因为 constructor 也是只执行一次。但,我个人还是建议把其放在 componentDidMount 里,这种方式是经过市场检验过的。)

2 Axios 的使用

2️⃣在 React 中,如何去发一个 AJAX 请求呢?

在 React 中,它本身不像 jQuery 那样,给我们直接封装了"AJAX 发送"的内置功能。

2️⃣-①:因此,我们需要安装一些第三方模块(如 Axios)来帮助我们发送 AJAX 请求;

2️⃣-②:打开 TodoList.js 文件,比如我想在 TodoList 首页,去发一个 AJAX 请求,我只需在顶部引入 axios 模块;

jsx 复制代码
import React, { Component, Fragment } from "react"; 

import TodoItem from "./TodoItem"; 

import axios from "axios"; // 🚀引入 axios 模块。

import "./style.css"; 

class TodoList extends Component {
  constructor(props) {
    super(props);
    this.state = {
      inputValue: "", 
      list: []
    };
    
    this.handleInputChange = this.handleInputChange.bind(this);
    this.handleBtnClick = this.handleBtnClick.bind(this);
    this.handleItemDelete = this.handleItemDelete.bind(this);
    
  }

  render() {
    return(
      <Fragment>
        <div>
          <label htmlFor="insertArea">请输入要进行的事项:</label>    
        
          <input 
            id="insertArea"
      
            className="input"
            value={this.state.inputValue}
            onChange={this.handleInputChange}
          />

          <button onClick={this.handleBtnClick}>
            提交
          </button>
        </div>

        <ul>
          {this.getTodoItem()}
        </ul>

      </Fragment>
    )
  }

  componentDidMount() { /*
  											2️⃣-③:然后在 componentDidMount 函数里,
  											去调用 axios 的相关方法获取数据;
                         */
    
    axios.get("/api/todolist") /*
    													 2️⃣-④:调用 axios 的 get 方法,去获取
                               地址为 /api/todolist 里的数据;
                                */
    
      .then(() => {alert("succ")}) // 2️⃣-⑤:一旦请求成功,我就返回 succ;
    
      .catch(() => {alert("error")}) // 2️⃣-⑥:否则,返回 error。
  }
  
  getTodoItem() {
    return this.state.list.map((item, index) => { 
      return( 
        <TodoItem 
        	key={index}
        
        	content={item}
        	index={index} 
        	itemDelete={this.handleItemDelete}
        />  
      )  
    })
  }
  
  handleInputChange(e) {
    const value = e.target.value
    
    this.setState(() => ({
      inputValue: value
    }))
  }

  handleBtnClick() {
    this.setState((prevState) => ({
      list: [...prevState.list, prevState.inputValue],  
      inputValue: ""        
    }))
  }

  handleItemDelete(index) { 
    this.setState((prevState) => {
      const list = [...prevState.list]
      list.splice(index, 1)
        
      return {list}
 
    })
  }
}

export default TodoList;

返回页面,检查元素,点击 Network 观察(我们发现,页面确实发送了一个指向 http://localhost:3000/api/todolist 的 AJAX 请求,说明 Axios 操作一切正常):

3 用 RAP2 模拟接口

3️⃣既然知道了如何发 AJAX 请求,接下来就可以选择自己模拟一个接口来跑通程序。

(💡本篇我们使用阿里的"接口管理"工具 RAP2 来 mock 数据~)

3️⃣-①:

3️⃣-②:将 RAP2 最终生成的"模拟数据接口"放到代码中;

jsx 复制代码
componentDidMount() {  
  axios.get("http://rap2api.taobao.org/app/mock/232799/api/todolist")     
    .then(() => {alert("succ")})
    .catch(() => {alert("error")})
}

3️⃣-③:返回页面查看(成功获取到数据);

4️⃣数据获取到后,就可以对数据进行加工了------将其放到 TodoList 的列表项里。

返回 TodoList.js 文件:

jsx 复制代码
import React, { Component, Fragment } from "react"; 

import TodoItem from "./TodoItem"; 

import axios from "axios"; // 🚀引入 axios 模块。

import "./style.css"; 

class TodoList extends Component {
  constructor(props) {
    super(props);
    this.state = {
      inputValue: "", 
      list: []
    };
    
    this.handleInputChange = this.handleInputChange.bind(this);
    this.handleBtnClick = this.handleBtnClick.bind(this);
    this.handleItemDelete = this.handleItemDelete.bind(this);
    
  }

  render() {
    return(
      <Fragment>
        <div>
          <label htmlFor="insertArea">请输入要进行的事项:</label>    
        
          <input 
            id="insertArea"
      
            className="input"
            value={this.state.inputValue}
            onChange={this.handleInputChange}
          />

          <button onClick={this.handleBtnClick}>
            提交
          </button>
        </div>

        <ul>
          {this.getTodoItem()}
        </ul>

      </Fragment>
    )
  }

  componentDidMount() { 
    axios.get("http://rap2api.taobao.org/app/mock/232799/api/todolist")  
    
      /*
      4️⃣-①:把请求的结果先在控制台打印出来,看看是些什么东西?
      先将这行代码注释掉:
      .then(() => {alert("succ")}) 
       */
    	.then((res) => {
    		console.log(res)
    	})
    
      .catch(() => {alert("error")})  
  }
  
  getTodoItem() {
    return this.state.list.map((item, index) => { 
      return( 
        <TodoItem 
        	key={index}
        
        	content={item}
        	index={index} 
        	itemDelete={this.handleItemDelete}
        />  
      )  
    })
  }
  
  handleInputChange(e) {
    const value = e.target.value
    
    this.setState(() => ({
      inputValue: value
    }))
  }

  handleBtnClick() {
    this.setState((prevState) => ({
      list: [...prevState.list, prevState.inputValue],  
      inputValue: ""        
    }))
  }

  handleItemDelete(index) { 
    this.setState((prevState) => {
      const list = [...prevState.list]
      list.splice(index, 1)
        
      return {list}
 
    })
  }
}

export default TodoList;

4️⃣-②:查看控制台(返回的结果中,白线框住的 data 部分是一个"数组 ");

4️⃣-③:既然 res.data.data 返回的是一个"数组",那需求(将"数组"里的每一项显示在"列表项"里)实现起来就很容易了;

jsx 复制代码
import React, { Component, Fragment } from "react"; 

import TodoItem from "./TodoItem"; 

import axios from "axios"; // 🚀引入 axios 模块。

import "./style.css"; 

class TodoList extends Component {
  constructor(props) {
    super(props);
    this.state = {
      inputValue: "", 
      list: []
    };
    
    this.handleInputChange = this.handleInputChange.bind(this);
    this.handleBtnClick = this.handleBtnClick.bind(this);
    this.handleItemDelete = this.handleItemDelete.bind(this);
    
  }

  render() {
    return(
      <Fragment>
        <div>
          <label htmlFor="insertArea">请输入要进行的事项:</label>    
        
          <input 
            id="insertArea"
      
            className="input"
            value={this.state.inputValue}
            onChange={this.handleInputChange}
          />

          <button onClick={this.handleBtnClick}>
            提交
          </button>
        </div>

        <ul>
          {this.getTodoItem()}
        </ul>

      </Fragment>
    )
  }

  componentDidMount() { 
    axios.get("http://rap2api.taobao.org/app/mock/232799/api/todolist")  
    
      .then((res) => {
        
        this.setState(() => ({ /*
        											 4️⃣-④:调用 setState 方法,传入一个"箭头函数",
        											 让"数据项"list 的值为 res.data.data。
                               */
          list: [...res.data.data]
        }))
      
      })
    
      .catch(() => {alert("error")})  
  }
  
  getTodoItem() {
    return this.state.list.map((item, index) => { 
      return( 
        <TodoItem 
        	key={index}
        
        	content={item}
        	index={index} 
        	itemDelete={this.handleItemDelete}
        />  
      )  
    })
  }
  
  handleInputChange(e) {
    const value = e.target.value
    
    this.setState(() => ({
      inputValue: value
    }))
  }

  handleBtnClick() {
    this.setState((prevState) => ({
      list: [...prevState.list, prevState.inputValue],  
      inputValue: ""        
    }))
  }

  handleItemDelete(index) { 
    this.setState((prevState) => {
      const list = [...prevState.list]
      list.splice(index, 1)
        
      return {list}
 
    })
  }
}

export default TodoList;

返回页面查看效果:

祝好,qdywxs ♥ you!

相关推荐
涔溪42 分钟前
Ecmascript(ES)标准
前端·elasticsearch·ecmascript
榴莲千丞1 小时前
第8章利用CSS制作导航菜单
前端·css
奔跑草-1 小时前
【前端】深入浅出 - TypeScript 的详细讲解
前端·javascript·react.js·typescript
羡与1 小时前
echarts-gl 3D柱状图配置
前端·javascript·echarts
guokanglun1 小时前
CSS样式实现3D效果
前端·css·3d
咔咔库奇1 小时前
ES6进阶知识一
前端·ecmascript·es6
前端郭德纲1 小时前
浏览器是加载ES6模块的?
javascript·算法
JerryXZR1 小时前
JavaScript核心编程 - 原型链 作用域 与 执行上下文
开发语言·javascript·原型模式
帅帅哥的兜兜1 小时前
CSS:导航栏三角箭头
javascript·css3
渗透测试老鸟-九青2 小时前
通过投毒Bingbot索引挖掘必应中的存储型XSS
服务器·前端·javascript·安全·web安全·缓存·xss