转载请注明出处,未经同意,不可修改文章内容。
🔥🔥🔥"前端一万小时"两大明星专栏------"从零基础到轻松就业"、"前端面试刷题",已于本月大改版,合二为一,干货满满,欢迎点击公众号菜单栏各模块了解。
javascript
涉及面试题:
如何在重新加载页面时保留数据?
编号:[react_18]
1 React 中发 AJAX 请求应该放在哪个"生命周期函数"里
❓紧接上一篇的代码,我们有一个新的需求:
我希望通过 AJAX 从一个"接口上"请求一个远程的数据(远程数据里边包含了 TodoList 的一些内容),然后把请求到的"远程数据"加载到本地,并显示在页面上的"列表项"里。
答:
🔗前置知识:《React 进阶------⑥ React 生命周期函数(上):弄懂所有"生命周期函数"》
《发出请求的"客户端":② 浏览器异步发送"HTTP 数据请求"------初识 AJAX》
《发出请求的"客户端":③ 浏览器异步发送"HTTP 数据请求"------XMLHttpRequest 对象详解》
1️⃣在 React 中,我们想发一个 AJAX 请求该怎么做呢?或者说,发 AJAX 请求相关的代码应该放在 TodoList.js
文件的哪个地方呢?
前端界到目前为止依然有讨论这个问题的声音。一个比较公认的,且不会报错的做法是:将 AJAX 请求相关的代码,放在"生命周期函数" componentDidMount
里。
因为在本页面上,AJAX 获取数据只需要获取一次。我们自然而然地就考虑到,React 的"生命周期函数"里,是否也有只执行一次的函数。
之前的文章我们讲过,所有"生命周期函数"里,只有两个函数只执行一次: componentWillMount
和 componentDidMount
。
-
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!