Editing Labels
Let's talk about forms first.
The concept of React is to always match the state of your app with the DOM. This has some implications for html forms. If you change an input field in a form, you break this concept: the dom and the state are no longer in sync.
So React won't let you edit an input field that has a
value
attribute added. Unless you specify what you want to do with the changes.In React there are controlled (if you specify a
value
) form inputs and uncontrolled form inputs.
// **** components/label-item.js ****
import React form 'react'
import ampersandMixin form 'ampersand-react-mixin'
export default React.createClass({
mixins: [ampersandMixin]
onDeletClick (event) { ... }
onEditClick () { ... },
onCancelClick () { ... },
render () {
const {label} = this.props
const cssColor = '#' + label.color
let content
if (label.editing) {
content = (
<form className='label'>
...
// ++++ 1. add a default value to the input label
// ++++ 2. we also add an onChange handler
<input name='name' type='text' value={label.name} onChange={this.onNameChange} />
</form>
)
} else {
content = (
<div className='label'>
...
</div>
)
}
return (<div>{content}</div>)
}
})
In normal W3C spec, the onchange event happens on blur (move out of the field). Here every time the value changes there's the event fired.The problematic of two-way binding
In Angular: as soon as you edit something you edit the model. But if the user clicks 'cancel', I have to revert this somehow.
He argues that form editing is an in-between state. You don't want to commit the change until the user is done editing (and it's validated).
React lets you track component-specific changes. State in a React component.
We will duplicate the state as a state of the component.
getInitialState
method gives you the initial state of the component.
// **** components/label-item.js ****
import React form 'react'
import ampersandMixin form 'ampersand-react-mixin'
export default React.createClass({
mixins: [ampersandMixin]
onDeletClick (event) { ... }
onEditClick () { ... },
onCancelClick () { ... },
// ++++ 1. define what happens in getInitialSate
getInitialState () {
const {name, color} = this.props.label
return {
name: name,
color: color
}
// so this is the internal state of the component
// it gets run on the initialising
},
// ++++ 2. onNameChange handler
onNameChange (event) {
// update the component state
// note: event is not raw the dom event but a simulation
this.setState({ // it's a React method, will re-render as well
name: event.target.value
})
},
render () {
const {label} = this.props
const cssColor = '#' + label.color
let content
if (label.editing) {
content = (
<form className='label'>
...
// ++++ 3. now we can use the component state
<input name='name' type='text' value={this.state.name} onChange={this.onNameChange} />
</form>
)
} else {
content = (
<div className='label'>
...
</div>
)
}
return (<div>{content}</div>)
}
})
React refs: it's a shortcut to reference an element (they, Henrik, others never really used it)