Mixing controlled/uncontrolled behaviour with `getDerivedStateFromProps` I have a component that displays a bunch of selectable options in a single row. It takes a pageSize prop from the parent component due to responsiveness requirements.
If the pageSize prop ever changes, I need to reset the currentPage (currently active page), which is held in state, to 0.
class OptionsRow extends React.PureComponent {
    state = {
        currentPage: 0
    }
    ...
    static getDerivedStateFromProps(props, state) {
        // Reset page on pageSize change
        return {
            currentPage: props.pageSize === state.prevPageSize
                ? state.currentPage
                : 0,
            prevPageSize: props.pageSize
        }
    }
    ...
}

This code works as intended.
The reason I'm asking for a review is that React in it's documentation warns against getDerivedStateFromProps so I'm not sure if this is a correct usage. In order to avoid derived state, it recommends making the component completely controlled/uncontrolled, so I should lift the currentPage up to the parent component. But is this really necessary? Is something wrong with my solution except for &quot;verbose code&quot;?
Thank you!
There is a small and subtle issue with your usage of getDerivedStateFromProps.

getDerivedStateFromProps is invoked right before calling the render
method, both on the initial mount and on subsequent updates. It should
return an object to update the state, or null to update nothing.

and

Note that this method is fired on every render, regardless of the cause.

Your implementation returns a new state object every render regardless, but it should return null when nothing needs to be updated. By returning a new state object each render then unnecessary re-renders may occur in children components if passed any values from this component's state as they would fail shallow object comparison.
class OptionsRow extends React.PureComponent {
  state = {
    currentPage: 0
  }

  ...

  static getDerivedStateFromProps(props, state) {
    if (props.pageSize !== state.prevPageSize) {
      // Reset page on pageSize change
      return {
        currentPage: 0,
        prevPageSize: props.pageSize
      }
    }

    // Nothing changed, return null to keep existing state
    return null;
  }

  ...

}

However, in 3+ years working with react I've not ever had any compelling reason to reach for getDerivedStateFromProps and the docs even specify

This method exists for rare use cases where the state depends on
changes in props over time.

The last bit bolded is the important bit. Your component's behavior appears to simply be an effect of a prop updating, i.e. a side-effect to reset state, and could be implemented via the componentDidUpdate lifecycle method.
Solution 1 - Bronze
class OptionsRow extends React.PureComponent {
  state = {
    currentPage: 0,
  }

  ...

  componentDidUpdate(prevProps, prevState) {
    // Reset page on pageSize change
    if (this.props.pageSize !== prevState.prevPageSize) {
      this.setState({
        currentPage: 0,
        prevPageSize: this.props.pageSize,
      });
    }
  }

  ...

}

But notice now that the state currentPage only needs to be reset when props.pageSize updates, so you can directly compare current and previous props and drop the storage of the &quot;last&quot; pageSize in local component state.
Solution 2 - Silver
class OptionsRow extends React.PureComponent {
  state = {
    currentPage: 0,
  }

  ...

  componentDidUpdate(prevProps) {
    // Reset page on pageSize change
    if (this.props.pageSize !== prevProps.pageSize) {
      this.setState({ currentPage: 0 });
    }
  }

  ...

}

There is still room for improvement though, using the third bullet point from the docs.

If you want to “reset” some state when a prop changes, consider either
making a component fully controlled or fully uncontrolled with a key
instead.

What this means is you can completely forego the getDerivedStateFromProps and componentDidUpdate logic to check and compare the props' pageSize value and simply use a react key that updates when the pageSize does.

When a key changes, React will create a new component instance rather
than update the current one.

Solution 3 - Gold
&lt;OptionsRow key={pageSize} pageSize={pageSize} /&gt;