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.
source to share
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.
source to share