Javascript ReactJS组件应该在什么时候进行AJAX调用以从道具更新状态?

Javascript ReactJS组件应该在什么时候进行AJAX调用以从道具更新状态?,javascript,ajax,reactjs,Javascript,Ajax,Reactjs,我有一个React组件,它显示有关实体的信息。实体的id通过属性传入。组件在“componentDidMount”中启动一个AJAX调用,以获取实体,并在调用完成/失败时更新状态 除了在实体id更改时(通过道具),组件不会获取新数据外,这一切都很好 我尝试过在“componentWillReceiveProps”中启动一个调用,但在那个阶段,组件仍然设置了旧的属性。我必须将nextrops传递给AJAX调用方法,这似乎不正确 让组件异步更新其状态以响应属性更改的最佳/最干净的方法是什么?我也是新

我有一个React组件,它显示有关实体的信息。实体的id通过属性传入。组件在“componentDidMount”中启动一个AJAX调用,以获取实体,并在调用完成/失败时更新状态

除了在实体id更改时(通过道具),组件不会获取新数据外,这一切都很好

我尝试过在“componentWillReceiveProps”中启动一个调用,但在那个阶段,组件仍然设置了旧的属性。我必须将nextrops传递给AJAX调用方法,这似乎不正确


让组件异步更新其状态以响应属性更改的最佳/最干净的方法是什么?

我也是新手,所以Flux体系结构对我来说有点吓人。我完全按照你说的做,使用
componentWillMount
通过AJAX加载初始数据,然后
componentWillReceiveProps
nextrops
在道具更改时再次加载新数据:

var Table = React.createClass({
  getInitialState: function() {
    return { data: [] };
  },

  componentWillMount: function(){
    this.dataSource();
  },

  componentWillReceiveProps: function(nextProps){
    this.dataSource(nextProps);
  },

  dataSource: function(props){
    props = props || this.props;

    return $.ajax({
      type: "get",
      dataType: 'json',
      url: '/products?page=' + props.page + "&pageSize=" + props.pageSize
    }).done(function(result){
      this.setState({ data: result });
    }.bind(this));
  },

  render: function() {
    return (
      <table className="table table-striped table-bordered">
        <Head />
        <Body data={this.state.data}/>
      </table>
    );
  }
});
var Table=React.createClass({
getInitialState:函数(){
返回{data:[]};
},
componentWillMount:function(){
this.dataSource();
},
组件将接收道具:函数(下一步){
this.dataSource(nextProps);
},
数据源:函数(道具){
道具=道具| | this.props;
返回$.ajax({
键入:“获取”,
数据类型:“json”,
url:“/products?page=”+props.page+“&pageSize=“+props.pageSize
}).完成(功能(结果){
this.setState({data:result});
}.约束(这个);
},
render:function(){
返回(
);
}
});

自React v16.3.0()以来,钩子
组件willmount
组件willreceiveprops
已被弃用

当您需要在组件第一次呈现()之后立即加载数据时,AJAX请求应该在
componentDidMount
钩子中完成。当您希望在某些道具更改后刷新数据时,必须使用
componentdiddupdate
hook

但您必须使用另外三个生命周期挂钩,以避免启动无限循环的请求/更新。假设您希望根据
props.category
更改更新帖子列表:

  • 状态
    应该有两个属性,
    类别
    当前类别
    ,在组件的构造函数上设置为null
  • 需要从新的
    props.category
    更新
    state.category
  • shouldComponentUpdate
    用于比较
    state.category
    state.currentCategory
    以确定是否应更新组件
  • 需要使用
    getSnapshotBeforeUpdate
    来确定
    componentDidUpdate
    是否应发出AJAX请求或更改
    状态。currentCategory
    值并完成更新周期
完整的代码如下所示():

import React,{Component,Fragment}来自'React';
从“axios”导入axios;
类Post扩展组件{
建造师(道具){
超级(道具);
此.state={
员额:[],
类别:空,
currentCategory:空
};
this._createMarkup=this._createMarkup.bind();
}
静态getDerivedStateFromProps(props,状态){
if(props.category!==state.category){
返回{
类别:道具类别
};
}
返回null;
}
componentDidMount(){
这是。_fetchData();
}
shouldComponentUpdate(下一步,下一步状态){
返回this.state.currentCategory!==nextState.category;
}
getSnapshotBeforeUpdate(prevProps,prevState){
返回prevState.currentCategory!==prevState.category;
}
componentDidUpdate(prevProps、prevState、dataDidFetch){
//dataDidFetch由getSnapshotBeforeUpdate返回
if(dataDidFetch){
这是我的国家({
currentCategory:this.state.category
});
}否则{
这是。_fetchData();
}
}
_fetchData(){
const category=this.state.category;
get(`/some/api/endpoint?category=${category}`)。然后(posts=>{
这是我的国家({
posts:posts.data
});
});
}
_创建标记(html){
返回{uuuhtml:html};
}
render(){
返回(
{this.state.posts.map(post=>(

))} ); } } 导出默认帖子;
我想你选择了最好的时刻。从文档中:使用此(
componentWillReceiveProps
)作为一个机会,在调用
render()
之前,通过使用
this.setState()
更新状态,对道具转换作出反应。可以通过此.props访问旧道具。在此函数中调用
this.setState()
,将不会触发其他渲染。另一方面,如果您希望在调用之前更新组件,我认为<>代码>组件-Debug Up/<代码>是您正在寻找的。我建议您考虑集中数据处理,以便更容易管理这些类型的流。然后将从存储区接收到的数据作为道具传递给子组件。@Edo只会将相同的问题推到父组件上。我认为情况并非如此,因为执行该操作的是一个位置(控制器),而不是多个位置。然后,存储(而不是组件)将执行AJAX调用(具有所有ID)并返回所有数据。然后将新数据作为道具传递将触发渲染。当您避免使用通量路径时,这几乎就是要使用的模式。一个重构要考虑在获取数据和渲染数据之间做出明显的分离,这将使ReDead()完全遗忘。
import React, { Component, Fragment } from 'react';
import axios from "axios";

class Post extends Component {

 constructor(props) {
    super(props);

    this.state = {
      posts: [],
      category: null,
      currentCategory: null
    };
   
   this._createMarkup = this._createMarkup.bind();
 }

  static getDerivedStateFromProps(props, state) {
    if (props.category !== state.category) {
      return {
        category: props.category
      };
    }
    return null;
  }

  componentDidMount() {
    this._fetchData();
  }

  shouldComponentUpdate(nextProps, nextState) {
    return this.state.currentCategory !== nextState.category;
  }

  getSnapshotBeforeUpdate(prevProps, prevState) {
    return prevState.currentCategory !== prevState.category;
  }

  componentDidUpdate(prevProps, prevState, dataDidFetch) {
   // dataDidFetch is returned by getSnapshotBeforeUpdate
    if (dataDidFetch) {
      this.setState({
        currentCategory: this.state.category
      });
    } else {
      this._fetchData();
    }
  }

  _fetchData() {
    const category = this.state.category; 
    axios.get(`/some/api/endpoint?category=${category}`).then(posts => {
      this.setState({
        posts: posts.data
      });
    });
  }

  _createMarkup(html) {
    return { __html: html };
  }

  render() {
    return (
      <Fragment>
        {this.state.posts.map(post => (
            <article className="post" key={post.id}>
              <h2>{post.title.rendered}</h2>
              <div dangerouslySetInnerHTML={this._createMarkup( post.content.rendered )} />
              <p className="post-link">
                <a href="{post.resource_link_url}">{post.resource_link_label}</a>
              </p>
            </article>        
          ))}
        </Fragment>
      );
  }
}

export default Post;