为什么选择在componentDidMount中使用ajax,而不是在componentWillMount中:
- react官方文档建议我们在componentDidMount阶段请求后台数据
之所以react推荐在componentDidMount钩子中使用而不是componentWillMount的原因:因为请求是异步的,所以无论你放在两个中的任何一个里面,几乎绝对都会在组件渲染之后,再进行数据渲染,也就是说避免不了二次渲染(第一次渲染为默认值,第二次为请求后的数据渲染),所以效果上放到哪里都一样,但是在DidMount中可以使用refs了。然后重要的是(是在Stack Overflow中的回答看到):未来的react版本可能会对componentWillMount进行调整,可能在某些情况下触发多次,所以官方是推荐在componentDidMount中进行请求。 当然放到willMount中可能会快那么几毫秒,毕竟先运行嘛。。。 - react的componentDidMount被调用的时候,组件已经被装载到DOM树上了,可以放心获取渲染出来的任何DOM,所以在这个阶段用AJAX获取数据来填充组件内容更为妥当。
- componentDidMount实在页面第一次渲染之后,这个时候插入数据是最好的,componentWillMountWill一般实在页面渲染之前做一些处理
使用axios:
安装axios
cnpm install axios -S
引入axios
import axios from 'axios'
使用:
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
ReactDOM.render(<App />, document.getElementById('root'));
App.js
import React, { Component } from 'react';
import axios from 'axios';
//定义常量ajax保存axios调用crea方法配置的东西
const ajax = axios.create({
//配置基本URL
baseURL: 'http://jsonplaceholder.typicode.com'
});
//interceptors拦截器
ajax.interceptors.request.use((config)=>{
console.log('开始请求');
//在请求开始阶段可更改请求config头header内的值
config.headers.blogToken = 'change the value';
//将改变后的值返回
return config;
});
//调用拦截器,在响应完成后打印请求结束
ajax.interceptors.response.use((resp)=>{
console.log('请求结束');
return resp;
})
class App extends Component {
constructor(){
super();
this.state = {
list:[],
isLoading: true,
title: '',
body: ''
}
}
componentDidMount(){//装载完成(生命周期函数)
// console.log('componentDidMount');
ajax.get('/posts')//调用get请求,并传递参数请求路径(url)
.then(resp=>{//成功时
if(resp.status===200&&resp.statusText==='OK'&&Array.isArray(resp.data)){
//通过判断请求响应的状态码和状态文本以及响应数据是否有值来判断是否响应成功
this.setState({//将响应数据赋值给state中的list数组
list:resp.data
});
}
})
.catch(err=>{//失败时,控制台打印错误
console.log(err)
})
.finally(()=>{//上面的then和catch方法无论是谁执行后都会调用finally方法
this.setState({//将state中的isLoading改为布尔值false
isLoading:false
})
})
}
onChangehandler=(e)=>{
this.setState({//利用对象键值对的原理将对应的值Value赋值给对应的键Key
[e.currentTarget.name]: e.currentTarget.value
})
}
onSubmit=(e)=>{
//阻止默认行为
e.preventDefault();//return false;//e.native.preventDefault
//阻止当前事件的冒泡
//e.native.stopImmediatePropagation;//e.stopInnediatePropagation;
//阻止冒泡
//e.stopPropagation
//在state中取得刚添加的title和body
const {title,body}=this.state;
//调用post方法,传递请求路径(url),和请求数据
ajax.post('/posts',{title,body})
.then(resp=>{//成功时,将新增的数据添加进响应返回的data,并用NewList保存起来
const newList = [resp.data,...this.state.list];
this.setState({//重置state中的list数组,将添加了新增数据的NewList赋给list数组
list: newList
});
})
.catch(err=>{//失败时,控制台打印错误
console.log(err)
})
}
render() {
return (
<div className="App">
{/* 判断isLoading的状态来确定是否显示loading提示 */}
{this.state.isLoading&&<div>loading</div>}
{/* 给form绑定onSubmit的处理事件,onSubmit只能绑定在form上,在button或submit上都没有作用 */}
<form action="" onSubmit={this.onSubmit}>
{/* 用Label把input包裹起来就避免了使用for属性来聚焦,点击Label都能够聚焦到input框内 */}
<label>title:<input type="text" name="title" value={this.state.title} onChange={this.onChangehandler}/></label>
<label>body:<textarea type="text" name="body" value={this.state.body} onChange={this.onChangehandler}/></label>
<input type="submit" value="on"/>
</form>
<ol>
{//遍历list数组,显示数据
this.state.list.map(item=>{
return (
<li key={item.id}>
<h2>{item.title}</h2>
<p>{item.body}</p>
</li>
)
})
}
</ol>
</div>
);
}
}
export default App;
代码优化----部分代码提出(代码切割)
新建一个文件保存提出部分代码:
services.js
import axios from 'axios';
const ajax = axios.create({
baseURL: 'http://jsonplaceholder.typicode.com'
});
ajax.interceptors.request.use((config) => {
console.log('开始请求');
config.headers.blogToken="sadfasdfdsafsdafqwer";
return config;
});
ajax.interceptors.response.use((resp) => {
console.log('请求结束');
return resp;
});
export const getPosts = () => {
return ajax.get('/posts')
}
export const postPosts = ({ title, body }) => {
return ajax.post('/posts', {
title,
body
})
}
提出代码后的App.js
import React, { Component } from 'react';
class App extends Component {
constructor() {
super();
this.state = {
list: [],
isLoading: true,
title: '',
body: ''
}
}
componentDidMount() {
console.log(this)
// hard code 硬编码
this.ajax.getPosts()
.then( resp => {
if ( resp.status === 200 && resp.statusText === 'OK' ) {
this.setState({
list: resp.data
});
}
})
.catch(err => {
console.log(err)
})
.finally(() => {
this.setState({
isLoading: false
})
})
}
handleFieldChange = (e) => {
console.log(e.currentTarget.name, e.currentTarget.value)
this.setState({
[e.currentTarget.name]: e.currentTarget.value
})
}
onSubmit = (e) => {
e.preventDefault();
// e.nativeEvent.preventDefault();
// e.nativeEvent.stopImmediatePropagation();
const {
title,
body
} = this.state;
this.ajax.postPosts({
title,
body
})
.then(resp => {
const newList =[
resp.data,
...this.state.list
]
this.setState({
list: newList
})
})
}
render() {
return (
<div className="App">
{
this.state.isLoading && <div>loading……</div>
}
<form onSubmit={this.onSubmit}>
<label>
title:
<input
onChange={this.handleFieldChange}
name="title"
value={this.state.title}
type="text"
/>
</label>
<label>
body:
<textarea
onChange={this.handleFieldChange}
name="body"
value={this.state.body}
/>
</label>
<button type="submit">提交</button>
</form>
<ol>
{
this.state.list.map(item => {
return (
<li key={item.id}>
<h3>{item.title}</h3>
<p>{item.body}</p>
</li>
)
})
}
</ol>
</div>
);
}
}
export default App;
将提出的文件在index.js中引入
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as ajax from './services';
React.Component.prototype.ajax = ajax;
ReactDOM.render(<App />, document.getElementById('root'));
网友评论