ReactJS:我有一个点击处理程序,跳过第一个道具方法

ReactJS: I have a click handler that is skipping the first props method

本文关键字:第一个 方法 程序 有一个 处理 ReactJS      更新时间:2023-09-26
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
           });
      });
  }

让我们来看看这里发生了什么:

  1. 组件接收到一个新的prop值。componentWillReceiveProps被调用
  2. 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方法被设计成不能在第一次挂载时运行,因为该方法侧重于比较新道具和旧道具。

    相关文章: