How to update derived state from props during reverder

I have a component:

React = require 'react'

module.exports = Toolbar = React.createClass

    initialUrl: React.PropTypes.string
    onUrlChange: React.PropTypes.func

  getInitialState: ->
    url: @props.initialUrl

  handleUrlChange: (e) ->

  handleUrlKeyUp: (e) ->
    if e.which == 13
      if (url = @state.url.trim())? and url isnt @props.initialUrl
        @setState {url}
    if e.which == 27
      @setState {url: @props.initialUrl}

  render: ->
    <div className="component-toolbar clearfix">
      <input type="text" value={@state.url} onChange={@handleUrlChange} onKeyUp={@handleUrlKeyUp}/>


The component works as follows:

  • It displays input from initialUrl

  • The user can change it.
  • When the user hits Enter, an event is fired onUrlChange

  • When the user presses esc, it @state.url

    reverts to the original value ( initialUrl


So far so good.

But when I change the props or the state of the top component it is coming from initalUrl

, then the component has the same state and is not overwritten. This is due to being getInitialState

called only once. But what is the correct approach to this problem?



source to share

1 answer

If you follow how the inputs react when working with initialValue, your current code has the same behavior. Only a reload will force it to change the url.

Alternatively, how about the parent control handle the state and add an onSubmit event?

module.exports = Toolbar = React.createClass

    url: React.PropTypes.string
    onChange: React.PropTypes.func
    onSubmit: React.PropTypes.func
    onReset: React.PropTypes.func

  handleUrlChange: (e) ->

  handleUrlKeyUp: (e) ->
    url = @props.url.trim()
    if e.which == 13
      if url?
    if e.which == 27

  render: ->
    <div className="component-toolbar clearfix">
      <input type="text" value={@props.url} onChange={@handleUrlChange} onKeyUp={@handleUrlKeyUp}/>


Of course this would change the api of your component, but fear not! Since you are starting with a stateless flexible component, you can wrap it in a component-based component that covers 90% of the use cases (example in es6 / 7).

class StatefulToolbar extends React.Component {
  static propTypes = {
    initialUrl: React.PropTypes.string,
    onUrlChange: React.PropTypes.func

    this.state = {url: props.initialUrl};

    return (
        onChange={(url) => this.setState({url})}
        onReset={() => this.setState({url: this.props.initialUrl})}
        onSubmit={(url) => this.props.onUrlChange(url)}


If you want to control how the value is updated based on some other event, you should create a wrapper for that specific situation, rather than making the toolbar complex.

Side note: propTypes, not proptypes.



All Articles