什么时候使用React的“ componentDidUpdate”方法?


109

我写了几十个React文件,从不使用componentDidUpdate方法。

是否存在何时需要使用此方法的典型示例?

我想要一些真实的例子,而不是简单的演示。

感谢你的回答!



一个简单的情况,当您希望设置加载时组件的初始状态。
拉杰什

@Rajesh你能解释一下还是给我一个例子?谢谢!
slideshowp2

1
我认为最常见的用例是当您具有直接在DOM上运行并与React耦合在一起的其他库(jQuery,D3 ...)时。在这种情况下,如果其他库需要执行DOM转换,则应使用componentDidUpdate来确保React的影子DOM已刷新为真实DOM。
豪尔赫

1
详细阐述@Jorge的评论:我认为最常见的情况是在React更新后从真实DOM中读取。例如,当您想知道DOM元素的确切尺寸或DOM元素在视口中的位置时。例如,您要作出反应的动画或过渡。我绝对建议不要在反应已呈现后使用jQuery更改DOM。让React +另一个库更改同一段DOM是一个坏主意。
wintvelt

Answers:


89

一个简单的示例是一个应用程序,该应用程序从用户收集输入数据,然后使用Ajax将所述数据上传到数据库。这是一个简化的示例(尚未运行-可能存在语法错误):

export default class Task extends React.Component {
  
  constructor(props, context) {
    super(props, context);
    this.state = {
      name: "",
      age: "",
      country: ""
    };
  }

  componentDidUpdate() {
    this._commitAutoSave();
  }

  _changeName = (e) => {
    this.setState({name: e.target.value});
  }

  _changeAge = (e) => {
    this.setState({age: e.target.value});
  }

  _changeCountry = (e) => {
    this.setState({country: e.target.value});
  }

  _commitAutoSave = () => {
    Ajax.postJSON('/someAPI/json/autosave', {
      name: this.state.name,
      age: this.state.age,
      country: this.state.country
    });
  }

  render() {
    let {name, age, country} = this.state;
    return (
      <form>
        <input type="text" value={name} onChange={this._changeName} />
        <input type="text" value={age} onChange={this._changeAge} />
        <input type="text" value={country} onChange={this._changeCountry} />
      </form>
    );
  }
}

因此,只要组件发生state更改,它将自动保存数据。也有其他方法可以实现它。componentDidUpdate当在DOM更新并且清空更新队列需要进行操作时,此功能特别有用。这也可能是复杂的最有用的rendersstate或DOM改变,或当你需要的东西是绝对的最后一件事要执行。

上面的示例虽然很简单,但是很可能证明了这一点。一种改进可能是限制自动保存可以执行的次数(例如,每10秒最多执行一次),因为现在它将在每次按键时运行。

我也在这个小提琴上做了一个演示,以进行演示。


有关更多信息,请参考官方文档

componentDidUpdate()更新发生后立即调用。初始渲染不调用此方法。

当组件已更新时,可借此机会在DOM上进行操作。只要将当前道具与以前的道具进行比较,这也是执行网络请求的好地方(例如,如果道具没有更改,则可能不需要网络请求)。


我认为this.setState({...}, callback)callback平等_commitAutoSave,您怎么看?所以,我认为这种情况可以使用componentDidUpdate方法,但不是必须的,对吗?小提琴
slideshowp2

1
是的,您可以使用回调,但是如果/如果有多个连续运行的setState,则问题变得更加棘手。
克里斯

感谢您的回答。因此,一种使用的情况componentDidUpdate是解决多个setState!还有其他想法吗?
slideshowp2

@novaline我看到他们在react-sound组件github.com/leoasis/react-sound/blob/master/src/index.js中使用它。.我不确定自己为什么使用它,但是我想我分享链接供您查看。
莎拉(Sarah)

3
这是一个很好的例子,但是它缺少React文档的关键建议。“只要将当前的道具与以前的道具进行比较,这也是一个进行网络请求的好地方(例如,如果道具未更改,则可能不需要网络请求)。” reactjs.org/docs/react-component.html#componentdidupdate 同样,每当setState在CDU中进行调用时,都应将该调用包装在条件逻辑中。
theUtherSide

5

有时,您可能会在构造函数或componentDidMount中的props中添加状态值,当props更改但组件已经挂载时,可能需要调用setState,因此componentDidMount将不会执行,构造函数也不会执行;在这种情况下,由于道具已更改,因此可以使用componentDidUpdate,可以在带有新道具的componentDidUpdate中调用setState。


2

我用过了 componentDidUpdate()海图。

这是此组件的一个简单示例。

import React, { PropTypes, Component } from 'react';
window.Highcharts = require('highcharts');

export default class Chartline extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      chart: ''
    };
  }

  public componentDidUpdate() {
    // console.log(this.props.candidate, 'this.props.candidate')
    if (this.props.category) {
      const category = this.props.category ? this.props.category : {};
      console.log('category', category);
      window.Highcharts.chart('jobcontainer_' + category._id, {
        title: {
          text: ''
        },
        plotOptions: {
          series: {
            cursor: 'pointer'
          }
        },
        chart: {
          defaultSeriesType: 'spline'
        },
        xAxis: {
          // categories: candidate.dateArr,
          categories: ['Day1', 'Day2', 'Day3', 'Day4', 'Day5', 'Day6', 'Day7'],
          showEmpty: true
        },
        labels: {
          style: {
            color: 'white',
            fontSize: '25px',
            fontFamily: 'SF UI Text'
          }
        },
        series: [
          {
            name: 'Low',
            color: '#9B260A',
            data: category.lowcount
          },
          {
            name: 'High',
            color: '#0E5AAB',
            data: category.highcount
          },
          {
            name: 'Average',
            color: '#12B499',
            data: category.averagecount
          }
        ]
      });
    }
  }
  public render() {
    const category = this.props.category ? this.props.category : {};
    console.log('render category', category);
    return <div id={'jobcontainer_' + category._id} style={{ maxWidth: '400px', height: '180px' }} />;
  }
}

2
componentDidUpdate(prevProps){ 

    if (this.state.authToken==null&&prevProps.authToken==null) {
      AccountKit.getCurrentAccessToken()
      .then(token => {
        if (token) {
          AccountKit.getCurrentAccount().then(account => {
            this.setState({
              authToken: token,
              loggedAccount: account
            });
          });
        } else {
          console.log("No user account logged");
        }
      })
      .catch(e => console.log("Failed to get current access token", e));

    }
}

1

更新发生后,将立即调用此生命周期方法。componentDidUpdate()方法最常见的用例是响应属性或状态更改而更新DOM。

您可以在此生命周期中调用setState(),但请记住,您需要将其包装在某种条件下,以检查状态或对先前状态的更改。setState()的不正确使用可能导致无限循环。看下面的示例,该示例显示了此生命周期方法的典型用法示例。

componentDidUpdate(prevProps) {
 //Typical usage, don't forget to compare the props
 if (this.props.userName !== prevProps.userName) {
   this.fetchData(this.props.userName);
 }
}

请注意,在以上示例中,我们正在将当前道具与以前的道具进行比较。这是为了检查道具是否从当前状态发生了变化。在这种情况下,如果道具未更改,则无需进行API调用。

有关更多信息,请参考官方文档:


发生什么情况this.fetchData is not a function
tomrlh

tomrlh这是一个函数调用
Kashif

0

当状态发生变化时,您需要调用副作用(例如对api的请求-获取,放置,发布,删除)。所以您需要致电,componentDidUpdate()因为componentDidMount()已经被致电。

在componentDidUpdate()中调用副作用之后,您可以根据中的响应数据将状态设置为新值then((response) => this.setState({newValue: "here"}))。请确保您需要检查prevPropsprevState避免无限循环,因为将状态设置为新值时,componentDidUpdate()将再次调用。

有两个地方可以称为最佳实践的副作用-componentDidMount()和componentDidUpdate()

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.