React: `getDerivedStateFromProps` concern

Created on 19 Feb 2018  路  2Comments  路  Source: facebook/react

Just read about getDerivedStateFromProps and am concerned the new api won't be flexible enough to cover some common use cases.

For instance, I have a scrolling tabs component. Whenever the selectedTabId prop changes I use browser apis to scroll that tab into view. What would be the best way to accomplish this without componentWillReceiveProps?

Currently code is something like this:

class Tabs extends React.Component {
  render() {
    return (
      <div className="tabs-container">
        {this.props.tabs.map(tab => (
          <div className="tab" key={tab.id} id={tab.id}>
            {tab.title}
          </div>
        ))}
      </div>
    );
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.selectedTabId !== this.props.selectedTabId) {
      document.querySelector(`#${nextProps.selectedTabId}`).scrollIntoView();
    }
  }
}

Most helpful comment

Thanks @iamdustan! I've actually haven't used the componentDidUpdate lifecycle method before but can see it's a much better solution than what I have been doing. Deprecating componentWillReceiveProps will probably help steer a lot of folks like me in a better direction with use cases like this one.

All 2 comments

For your current example you likely want componentDidUpdate. componentWillRecieveProps is called _before_ the DOM is actually updated so you have a condition where you may attempt to scroll an item into view prematurely.

  componentDidUpdate(prevProps) {
    if (prevProps.selectedTabId !== this.props.selectedTabId) {
      document.querySelector(`#${nextProps.selectedTabId}`).scrollIntoView();
    }
  }

Alternatively you could consider a ref rather than DOM APIs in this example:

class Tabs extends React.Component {
  render() {
    return (
      <div className="tabs-container">
        {this.props.tabs.map(tab => (
          <div
            className="tab"
            key={tab.id}
            ref={tab.id === this.props.selectedTabId ? this.scrollRef : null}
          >
            {tab.title}
          </div>
        ))}
      </div>
    );
  }

  scrollRef(ref) {
    if (ref) {
      ref.scrollIntoView();
    }
  }
}

Thanks @iamdustan! I've actually haven't used the componentDidUpdate lifecycle method before but can see it's a much better solution than what I have been doing. Deprecating componentWillReceiveProps will probably help steer a lot of folks like me in a better direction with use cases like this one.

Was this page helpful?
0 / 5 - 0 ratings