【问题标题】:not sure why this asynchronous call in react is working不知道为什么反应中的这个异步调用有效
【发布时间】:2020-05-24 23:30:54
【问题描述】:

我正在玩 reactjs,这就是我正在做的事情: 正在从 API 检索数据并显示数据 使用 axios 调用 API。 我知道 axios 调用是异步的并且是基于 Promise 的。

我的理解是在 react 'setState' 中只能在组件挂载后调用 (发生在 componentDidMount 中)。 所以对 API 的调用是在 'componentDidMount' 中进行的

我不清楚的是:为什么会这样,为什么要显示数据?

我正在阅读 here 'render' 在 'componentDidMount' 完成之前被触发

所以鉴于“render”在“componentDidMount”之前,我很困惑为什么数据加载并显示正常?

我还查看了this site,它使用一些标志来确定数据是否已加载,然后决定是否显示微调器 我也不必做任何这样的事情 因此,虽然它确实显示数据,但我相信还有更多...

代码如下:

class StudentsPage extends React.Component{
constructor(props){
    super(props);

    this.state = {
        isLoaded: false,
        studentListArray: []
    }
}


 componentDidMount(){
       /** now get results from api call and need to set the result to the state of this class */

       /** setting state MUST happen using setState and no other way - this is important */
       /** NOTE below call to setState will ONLY modify the attribute 'studentListArray' of state
        *  if there were other attributes / properties in state they would not get impacted / modified
        *  so setState is more like setters for individual properties 
        *  you can change multiple properties in one setter OR call setState for each property you want to change !
        */

     /** define the endpoint to be called */
    const baseUrl = process.env.REACT_APP_API_URL + "/studentList/";
    axios.get(baseUrl).then(({data}) => {
        this.setState(
            { studentListArray: data }
       );            
    })

  }
render(){ 
    return(
        <React.Fragment>
        <table className="table">
            <thead>
                <tr>
                    <th>Sudent ID</th>
                    <th>Student subject</th>
                </tr>
            </thead>

            <tbody>
                {this.state.studentListArray.map((student) => {
                    return (<tr>
                        <td>{student.id}</td>
                        <td>{student.subject}</td>
                    </tr>);

                })}
            </tbody>
        </table>
        </React.Fragment>
    );
}
}

【问题讨论】:

  • 这完全符合预期。我建议在你的render 方法中加入一些console.logs,看看this.state.studentListArray 最初是什么(空数组),然后在你调用this.setState 之后。它可能以您描述的方式出现的原因是 b/c 最初您的数组是空的,因此它不会破坏或呈现任何内容,一旦您收到回复并更新studentListArray,它将立即重新渲染。服务器的响应是即时的,因此可以快速重新渲染。
  • 另外,一种证明一切按预期工作的方法,将this.state.studentListArray 的初始值更改为null 并注意代码中断,因为axios.get 调用尚未完成获取和更新第一次渲染之前的状态。
  • 为什么有效? ... 异步结果修改状态(使用 setState) - 任何 stateprops 更改都是重新渲染的原因(更新视图) - 这样您就可以说使用 setState (使用不同的数据然后当前)强制重新渲染(显示具有新数据/状态的新视图)
  • 谢谢,我想我错过的是'setState'会再次调用'render',而且我对方法执行的顺序也有误(componentDidMount 然后渲染(我的假设)与实际顺序渲染 >> componentDidMOunt >> 渲染(如果状态改变)
  • 我将针对相同代码的变体发布一个单独的问题,但失败了

标签: javascript reactjs


【解决方案1】:

当一个基于类的组件被挂载时,它的生命周期方法按以下顺序执行:

  1. constructor()
  2. static getDerivedStateFromProps()
  3. render()
  4. componentDidMount()

在您的情况下,在安装 StudentPage 组件后,它会立即尝试获取数据,然后触发组件更新/重新渲染。

当组件重新渲染时,它会按以下顺序调用以下生命周期方法:

  1. static getDerivedStateFromProps
  2. shouldComponentUpdate()
  3. render()
  4. getSnapShotBeforeUpdate()
  5. componentDidUpdate()

如果您在render()componentDidMount()componentDidUpdate() 中放置一个断点或简单的console.log(),您将能够更清楚地看到这一点。

这纯粹是我的猜测,但您调用的(我假设是本地的)服务器可能会更快地响应您期望的数据,因此数据似乎很容易获得在第一次安装时。

如果您想了解更多有关 React 生命周期方法的信息,请随时参考 the official React documentation

【讨论】:

  • 谢谢,是的,我缺少的是当状态改变时渲染确实会再次被调用,并且我的方法执行顺序错误(componentDidMount 然后渲染)
猜你喜欢
  • 1970-01-01
  • 2020-10-23
  • 1970-01-01
  • 2019-06-22
  • 1970-01-01
  • 2020-01-27
  • 1970-01-01
  • 2012-01-30
  • 1970-01-01
相关资源
最近更新 更多