How to update derived state from props during reverder

I have a component:

React = require 'react'

module.exports = Toolbar = React.createClass

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

  getInitialState: ->
    url: @props.initialUrl

  handleUrlChange: (e) ->
    @setState(url: e.target.value)

  handleUrlKeyUp: (e) ->
    if e.which == 13
      e.target.blur()
      if (url = @state.url.trim())? and url isnt @props.initialUrl
        @props.onUrlChange?(url)
        @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}/>
    </div>

      

The component works as follows:

  • It displays input from initialUrl

    inside.
  • 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?

Thank.

+3


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

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

  handleUrlChange: (e) ->
    @props.onChange(e.target.value)

  handleUrlKeyUp: (e) ->
    url = @props.url.trim()
    if e.which == 13
      e.target.blur()
      if url?
        @props.onChange?(url)
        @props.onSubmit?(url)
    if e.which == 27
      @props.onReset()

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

      

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
  };

  constructor(props){
    super();
    this.state = {url: props.initialUrl};
  }

  render(){
    return (
      <Toolbar 
        value={this.state.url}
        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.

+2


source







All Articles