Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Turning props into state after initialisation with GetDerivedStateFromProps?

I have the following, super-simple Component:

export default class Editor extends Component {
  constructor(props) {
    super(props);

    this.state = { field: "Some Initial Text" };

    this.handleChangeField = this.handleChangeField.bind(this);
  }

  handleChangeField(e) {
    this.setState({field: e.target.value});
  }

  render() {
    return (
        <div>
          <input type="text" name="word" value={this.state.field} onChange={this.handleChangeField} />
          {this.state.field}
        </div>
    );
  }
}

It just has a field. The field can be edited by the user. Depending on what the user clicks on in a sibling-component, the above component will receive a prop called fieldValue which will then be what's shown in the input field. Since the user should be able to edit this input field, I cannot simply put the prop into the input-field directly, but use state. So I initialise the components state from the prop.

However, this prop might change even after the component is initialised. That is, it will not only be an initial value, but might change during runtime, depending on what the user clicks on in the sibling-components.

How would I solve something like this in React 16.3, with ComponentWillReceiveProps being deprecated? I have tried looking into GetDerivedStateFromProps, but I don't fully understand how to use it.

like image 275
R. Kohlisch Avatar asked Jan 17 '26 01:01

R. Kohlisch


1 Answers

I wouldn't go for trying to sync uncontrolled component with controlled component, as the logic can get crazy when the component scales.

With that said, if you really want to track prop changes and update state accordingly you could use componentDidUpdate but make sure you got some valid conditions before updating the state.

Here is a running example:

class Editor extends React.Component {

  state = { field: this.props.defaultValue };

  componentDidUpdate(prevProps) {
    const { defaultValue } = this.props;
    if (prevProps.defaultValue !== defaultValue) {
      this.setState({ field: defaultValue });
    }
  }

  handleChangeField = (e) => {
    this.setState({ field: e.target.value });
  }

  render() {
    return (
      <div>
        <input type="text" name="word" value={this.state.field} onChange={this.handleChangeField} />
        {this.props.defaultValue}
      </div>
    );
  }
}

class App extends React.Component {
  state = { value: 'A default value' }

  handleChange = ({ target }) => this.setState({ value: target.value })

  render() {
    const { value } = this.state;
    return (
      <div>
        <h3>App </h3>
        <input type="text" value={value} onChange={this.handleChange} />
        <hr />
        <h3>Editor</h3>
        <Editor defaultValue={value} />
      </div>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"/>
like image 138
Sagiv b.g Avatar answered Jan 19 '26 14:01

Sagiv b.g



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!