【问题标题】:Double rendering in React with asynchronous call in componentDidMount causing errorReact中的双重渲染与componentDidMount中的异步调用导致错误
【发布时间】:2018-08-10 03:34:14
【问题描述】:

我正在构建一个具有文章索引页面的博客应用程序,您可以从那里单击文章以查看文章或编辑文章。

如果您从索引页面转到编辑页面,它工作得很好,因为我已经拥有了所有的文章状态。但是,如果我在进入编辑文章页面后刷新,我将不再拥有所有文章的状态。

这是一个问题,因为我在我的编辑文章页面的 componentDidMount 中进行了异步 recieveSingleArticle 调用,然后我 setState 所以我的表单被预填充。有一个双重渲染会导致“Uncaught TypeError: Cannot read property 'title' of undefined”错误,大概是在文章被接收到状态之前的第一次渲染期间。

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

    this.state = {title: "", body: "", imageFile: ""};

    this.handleChange = this.handleChange.bind(this);
    this.handlePublish = this.handlePublish.bind(this);
    this.handleFile = this.handleFile.bind(this);
    this.handleCancel = this.handleCancel.bind(this);
  }

  componentDidMount() {
    const { article, requestSingleArticle } = this.props;

    requestSingleArticle(this.props.match.params.articleID)
    .then(() => {
      this.setState({
        title: article.title,
        body: article.body,
        imageFile: article.imageFile
      });
    });
  }
...

我尝试将我的异步调用包装在“if (this.props.article)”中,但没有奏效。是否有处理此类问题的最佳方法?任何建议都非常感谢!

更新:

另一个可行的解决方案是除了 componentDidMount 之外还有一个 componentDidUpdate。如果 this.props.article 存在,则检查 componentDidMount,如果存在,则 setState。在 componentDidUpdate 中,将 setState 包装在以下条件中:

if (!prevProps.article && this.props.article)

【问题讨论】:

  • 尝试将 API 调用移至 constructor ;)
  • 您可能在使用路由器吗?您将 ArticleList 中的 id 作为道具传递给 ArticleEdit。并且当您刷新(浏览器)编辑页面时,不会获取任何数据?如果是这样,那么作为 props 传递的文章 id 将为 null 从而使 http 请求失败
  • 感谢你们!添加到我的构造函数中确实起到了作用。

标签: javascript reactjs


【解决方案1】:

在调用异步操作之前检查文章是否存在于道具中

componentDidMount() {
  const { article, requestSingleArticle } = this.props;
  if (!(article && requestSingleArticle)) return; // this line
  requestSingleArticle(this.props.match.params.articleID)
  .then(() => {
    this.setState({
      title: article.title,
      body: article.body,
      imageFile: article.imageFile
    });
  });
}

由于你没有从这个方法中得到任何渲染,这意味着在生命周期方法componnetDidMount中还没有获得道具。因此,您可以像这样使用componentWillReceiveProps

componentWillReceiveProps(nextProp) {
  // this line here will check the article props' status so that
  // we will not use setState each time we get a prop
  if (this.props.article === nextProp.article) return;

  // rest is just the same code from above
  const { article, requestSingleArticle } = nextProp;
  if (!(article && requestSingleArticle)) return; // this line
  requestSingleArticle(this.props.match.params.articleID)
  .then(() => {
    this.setState({
      title: article.title,
      body: article.body,
      imageFile: article.imageFile
    });
  });
}

【讨论】:

  • 不幸的是,如果您从 ArticleEdit 页面中刷新页面,它不会预填充表单。
  • 那是因为当你的组件刚刚挂载时,你的 prop 中没有文章。而不是componentDidMount,我认为你应该使用componentWillReceiveProps。这样,如果它肯定会在组件的生命周期内出现,您肯定会获得文章道具
  • 啊 componentWillReceiveProps 成功了!我想我可能想在前进时考虑 getDerivedStateFromProps
  • @akorn3000 在这种情况下请将答案标记为正确!这样其他面临同样问题的人就知道什么解决了他们的问题:)
猜你喜欢
  • 1970-01-01
  • 2020-07-18
  • 1970-01-01
  • 2020-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多