ReactJS:我有一个点击处理程序,跳过第一个道具方法
ReactJS: I have a click handler that is skipping the first props method
import React from 'react';
import ReactDOM from 'react-dom';
import axios from 'axios';
var mode=[ 'recent', 'alltime'];
class Header extends React.Component {
constructor(){
super()
}
render(){
return <h2>Free Code Camp Leader board</h2>
}
}
class Leader extends React.Component {
constructor(props){
super(props)
this.state = {
users: [],
val: props.m
}
}
componentWillReceiveProps(props){
this.setState({val: props.m})
this.ajax();
}
componentWillMount() {
this.ajax();
}
ajax(){
this.serverRequest =
axios.get("https://fcctop100.herokuapp.com/api/fccusers/top/"+this.state.val)
.then((result) => {
console.log(result.data);
var leaders = result.data;
this.setState({
users: leaders
});
});
}
componentWillUnmount() {
this.serverRequest.abort();
}
render() {
console.log(this.state, this.props)
return (
<div className='container'>
<div className="tbl">
<table className="table">
<thead>
<tr>
<th>Name</th>
<th>Recent </th>
<th>Alltime</th>
</tr>
</thead>
<tbody>
{this.state.users.map(function(data, index){
return (<tr key={index}><td><img src={data.img} className="img img-thumbnail" width="50"/>{data.username}</td>
<td id='recent'>{data.recent}</td>
<td id='alltime'>{data.alltime}</td></tr>)
})}
</tbody>
</table>
</div>
</div>
)
}
}
class App extends React.Component{
constructor() {
super(),
this.state={val: mode[0]},
this.onClick= this.onClick.bind(this)
}
onClick() {
this.setState({val: this.state.val === mode[0]? mode[1] : mode[0]})
}
render() {
return (
<div>
<div className='header'>
<Header />
<button onClick={this.onClick} >{this.state.val==mode[0]? mode[1] : mode[0]}</button>
</div>
<div>
<Leader m={this.state.val} />
</div>
</div>
);
}
}
export default App;
由于某些原因,应用程序加载正常,但在点击按钮内部的第一次点击时,它什么也不做;然而,除了与按钮上的文本不同步之外,它在随后的点击中工作得很好。使用componentWillReceiveProps方法是否有问题?
首先,组件挂载时不会调用componentWillReceiveProps
。检查一下医生。因此,您应该调用componentDidMount
中的第一个ajax
调用。
componentDidMount(){
this.setState({val: this.props.m},this.ajax);
}
第二,您应该意识到setState
方法是异步的。在你的componentWillReceiveProps
中,你应该调用this.ajax
方法作为this.setState
方法的回调,以确保你的this.state.val
在调用ajax
时已经更新。
componentWillReceiveProps(nextProps){
this.setState({val: nextProps.m},this.ajax);
}
还有一件事,确保ajax
方法绑定到组件实例。
问题是你如何做你的AJAX和管理React状态。让我们看一下:
componentWillReceiveProps(props){
this.setState({val: props.m})
this.ajax();
}
ajax(){
this.serverRequest =
axios.get("https://fcctop100.herokuapp.com/api/fccusers/top/"+this.state.val)
.then((result) => {
console.log(result.data);
var leaders = result.data;
this.setState({
users: leaders
});
});
}
让我们来看看这里发生了什么:
- 组件接收到一个新的prop值。
componentWillReceiveProps
被调用 - 在
componentwillReceiveProps
内部发生的第一件事是你调用setState
。这很好……除了state
不会更新,直到在componentWillReceiveProps
完全完成运行后。来自React文档:
setState()不会立即改变它。状态,但会创建挂起的状态转换。访问。状态调用此方法后可能返回现有值。
所以目前这没有做什么- state
保持完全一样,因为它是暂时的;它的价值过时了!我不确定它是否明确记录,但据我所知,在this.setState
之后,只有可靠的地方访问state
是在render()
函数。
- 调用
-
this.ajax()
。在ajax()
内部是一个axios.get()
调用。注意这里是如何使用this.state.val
来格式化URL的。在这一点上,组件state
仍然没有更新,所以你发送一个GET请求到错误的URL。 -
ajax()
结束运行,componentWillReceiveProps()
也结束运行。在此之后的某个时间,state
将实际更新。但是,您已经使用错误的URL发起了AJAX调用,所以现在为时已晚!
简而言之:this.setState
没有立即更新state
,这是你的问题。您总是会看到AJAX的结果"一个状态"太老。
如何修复
其实很简单。而不是ajax
依赖于this.state.val
在它被调用时是什么,重写它以接受它作为一个参数。
componentWillReceiveProps(props){
this.setState({val: props.m})
this.ajax(props.m);
}
// You have to modify componentWillMount() too because it should pass a parameter
// No need to access state though - just use the prop directly
componentWillMount() {
this.ajax(this.props.val);
}
// ajax() now accept a parameter it will use to construct its URL
ajax(value){
this.serverRequest =
axios.get("https://fcctop100.herokuapp.com/api/fccusers/top/"+value)
.then((result) => {
console.log(result.data);
var leaders = result.data;
this.setState({
users: leaders
});
});
}
其他notes
这是非常奇怪的你接受改变props
,然后因为某种原因将它们转移到state
。你可以直接使用props
,无论何时他们改变,使用componentWillReceiveProps()
做你的AJAX调用或任何。
componentWillReceiveProps方法被设计成不能在第一次挂载时运行,因为该方法侧重于比较新道具和旧道具。
- 关闭第二个事件源上的第一个事件源's onopen方法
- 使用filter和map方法将数组中某些元素的第一个字母大写-JavaScript
- Jqgrid在第一个下拉索引chnage方法后未重新加载
- 为什么 .on() 方法不执行第一个处理程序
- JavaScript:获取第一个月前 6 个月的日期的最简单方法
- 为什么在给出第一个结果后仍然调用此方法
- 有没有更好的方法来访问用JQuery选择器选择的第一个元素
- JAVASCRIPT:分配给另一个方法的方法与第一个方法的变化值相同,改变第二个方法
- jQuery slice() 方法 在 html 中选择元素(第一个/最后一个)
- (Js)数字方法在第一个数字后添加逗号并删除逗号后的2个数字??有没有
- 为什么当我调用 Meteor.setTimeout() 时,我后续的 Meteor 方法调用不会等待第一个方法完成
- 将第一个(对象的)数组的属性复制到不同长度的另一个(对象)数组的Javascript方法
- 获取数组中满足 Javascript 条件的第一个元素的高阶方法
- 从所有单词中替换,即使用破折号分隔,第一个字符用大写[更简单的方法]
- 为什么.replace 方法使用正斜杠字符将第一个参数括起来
- AngularJS + Ionic - 如何从第一个控制器调用第二个控制器上的方法
- ECMA5 数组方法 - 查找数组中某个类型的第一个对象
- jquery:如果第一个选择器返回为空,有没有一种简明的方法可以有条件地使用第二个选择器
- 在第一个方法完成后运行方法
- 为什么$(this).val()在第二个方法中给我第一个方法的值