diff --git a/docs/forms.md b/docs/forms.md index a8c10519..b9d8c0c6 100644 --- a/docs/forms.md +++ b/docs/forms.md @@ -9,7 +9,7 @@ redirect_from: "tips/controlled-input-null-value.html" Form components such as ``, ``, and `` differ from other native components because they can be mutated via user interactions. These components provide interfaces that make it easier to manage forms in response to user interactions. -Two types of form components: +There are two types of form components: * Controlled Components * Uncontrolled Components @@ -20,15 +20,19 @@ You can jump directly to examples. A **controlled** form component provides a `value` prop. A **controlled** component does not maintain its own internal state; the component renders purely based on props. -```javascript +```javascript{5} render() { - return ; + return ( + + ); } ``` -User input has no effect on the rendered element because React has declared the value to be "Hello!". +If you try to run this example, you will notice that the input doesn't change as you type. This is because the component has declared the input's `value` to always be `"Hello!"`. -To update the value in response to user input, you would use the `onChange` event to save the new value, then pass that to the `value` prop of the form: +To update the value in response to user input, you would use the `onChange` event to save the new value, then pass that to the `value` prop of the input: ```javascript{10,22,23} class Form extends React.Component { @@ -54,34 +58,53 @@ class Form extends React.Component { placeholder="Hello!" value={this.state.value} onChange={this.handleChange} /> - Submit + + Submit + ); } } -ReactDOM.render(, document.getElementById('root')); +ReactDOM.render( + , + document.getElementById('root') +); ``` -[Try it on CodePen.](https://codepen.io/ericnakagawa/pen/QKkJva?editors=0010) +[Try it on CodePen.](https://codepen.io/gaearon/pen/NRmBmq?editors=0010) In this example, we are accepting the value provided by the user and updating the `value` prop of the `` component. This pattern makes it easy to implement interfaces that respond to or validate user interactions. For example: -```javascript +```javascript{3} handleChange(event) { - this.setState({value: event.target.value.substr(0, 140)}); + this.setState({ + value: event.target.value.substr(0, 140) + }); } ``` This would accept user input and truncate the value to the first 140 characters. +Controlled components also let us reset inputs to arbitrary values by setting the state: + +```javascript{3} + handleClearClick() { + this.setState({ + value: '' + }); + } +``` + ### Potential Issues With Checkboxes and Radio Buttons -Be aware that, in an attempt to normalize change handling for checkbox and radio inputs, React uses a `click` event in place of a `change` event. For the most part this behaves as expected, except when calling `preventDefault` in a `change` handler. `preventDefault` stops the browser from visually updating the input, even if `checked` gets toggled. This can be worked around either by removing the call to `preventDefault`, or putting the toggle of `checked` in a `setTimeout`. +Be aware that, in an attempt to normalize change handling for checkbox and radio inputs, React listens to a `click` browser event to implement the `onChange` event. + +For the most part this behaves as expected, except when calling `preventDefault` in a `change` handler. `preventDefault` stops the browser from visually updating the input, even if `checked` gets toggled. This can be worked around either by removing the call to `preventDefault`, or putting the toggle of `checked` in a `setTimeout`. ## Uncontrolled Components -Form components that do not provide a `value` prop are *uncontrolled*. +Form components that do not provide a `value` prop are **uncontrolled**. The example below renders an `` control with an empty value. Any user input will be immediately reflected by the rendered element. @@ -95,7 +118,7 @@ An **uncontrolled** component manages its own state. If you wanted to listen to updates to the value, you could use the `onChange` event just like you can with controlled components. However, you would _not_ pass the value you saved to the component. -```javascript{10,22} +```javascript{25} class Form extends React.Component { constructor(props) { super(props); @@ -105,6 +128,8 @@ class Form extends React.Component { } handleChange(event) { + // Note: with uncontrolled inputs, you don't + // have to put the value in the state. this.setState({value: event.target.value}); } @@ -115,21 +140,29 @@ class Form extends React.Component { render() { return ( - - Submit + + Submit + ); } } -ReactDOM.render(, document.getElementById('root')); +ReactDOM.render( + , + document.getElementById('root') +); ``` -[Try it on CodePen.](https://codepen.io/ericnakagawa/pen/XjxyoL?editors=0010) +[Try it on CodePen.](https://codepen.io/gaearon/pen/pEBOJR?editors=0010) + +While this example puts value in the state so we can later read it in `handleSubmit()`, uncontrolled form components don't require this. You may completely omit an `onChange` handler and instead read the input value using [DOM references](/react/docs/refs-and-the-dom.html), an advanced feature discussed later. -###Default Values +### Default Values To initialize an uncontrolled component with a non-empty value, you can supply a `defaultValue` prop. @@ -190,7 +223,7 @@ Since this method describes the view at any point in time, the value of the text In HTML, the value of `` is usually set using its children: ```html - + This is the description. ``` @@ -220,16 +253,16 @@ To make an uncontrolled component, `defaultValue` is used instead. > > You can pass an array into the `value` attribute, allowing you to select multiple options in a `select` tag: ``. -### Imperative operations +### Imperative Operations If you need to imperatively perform an operation, you have to obtain a [reference to the DOM node](/react/docs/more-about-refs.html#the-ref-callback-attribute). For instance, if you want to imperatively submit a form, one approach would be to attach a `ref` to the `form` element and manually call `form.submit()`. ## Examples -### Basic Controlled Input +### Controlled Input -```javascript +```javascript{10,23,24} class Form extends React.Component { constructor(props) { super(props); @@ -237,6 +270,7 @@ class Form extends React.Component { this.handleChange = this.handleChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } + handleChange(event) { this.setState({value: event.target.value}); } @@ -254,21 +288,25 @@ class Form extends React.Component { value={this.state.value} onChange={this.handleChange} /> - Submit + + Submit + ); } } -ReactDOM.render(, document.getElementById('root')); +ReactDOM.render( + , + document.getElementById('root') +); ``` -[Try this on CodePen.](https://codepen.io/ericnakagawa/pen/JRmZjz?editors=0010) - +[Try it out on CodePen.](https://codepen.io/gaearon/pen/JRVaYB?editors=0010) -### Basic Controlled Textarea +### Controlled Textarea -```javascript +```javascript{10,22,23} class Form extends React.Component { constructor(props) { super(props); @@ -293,20 +331,26 @@ class Form extends React.Component { value={this.state.value} onChange={this.handleChange} /> - Submit + + + Submit + ); } } -ReactDOM.render(, document.getElementById('root')); +ReactDOM.render( + , + document.getElementById('root') +); ``` -[Try this on CodePen.](https://codepen.io/ericnakagawa/pen/kkAQPp?editors=0010) +[Try it out on CodePen.](https://codepen.io/gaearon/pen/NRmLxN?editors=0010) -### Basic Uncontrolled Select +### Controlled Select -```javascript +```javascript{10,20} class Form extends React.Component { constructor(props) { super(props); @@ -331,20 +375,25 @@ class Form extends React.Component { Banana Cranberry - Submit + + Submit + ); } } -ReactDOM.render(, document.getElementById('root')); +ReactDOM.render( + , + document.getElementById('root') +); ``` -[Try this on CodePen.](https://codepen.io/ericnakagawa/pen/pExQbL?editors=0010) +[Try it out on CodePen.](https://codepen.io/gaearon/pen/qawrbr?editors=0010) -### Basic Radio Button +### Uncontrolled Radio Button -```javascript +```javascript{25,34,35,44} class Form extends React.Component { constructor(props) { super(props); @@ -365,38 +414,53 @@ class Form extends React.Component { return ( - Option A - + Option B - + Option C - - Submit + + + + Submit + ); } } -ReactDOM.render(, document.getElementById('root')); +ReactDOM.render( + , + document.getElementById('root') +); ``` -[Try this on CodePen.](https://codepen.io/ericnakagawa/pen/WGaYVg?editors=0010) +[Try it out on CodePen.](https://codepen.io/gaearon/pen/ozOPLJ?editors=0010) +### Uncontrolled Checkbox -### Basic Uncontrolled Checkbox - -```javascript +```javascript{37,45,46,54} class Form extends React.Component { constructor(props) { super(props); @@ -406,10 +470,16 @@ class Form extends React.Component { } handleChange(event) { - let value = event.target.value; - let checked = this.state.checked; // copy - if (!checked[value]) { checked[value] = true; } else { checked[value] = false; } - this.setState({checked: checked}) + const value = event.target.value; + // Copy the object so we don't mutate the old state. + // (This requires an Object.assign polyfill): + const checked = Object.assign({}, this.state.checked) + if (!checked[value]) { + checked[value] = true; + } else { + checked[value] = false; + }; + this.setState({checked}); } handleSubmit(event) { @@ -424,36 +494,43 @@ class Form extends React.Component { return ( - Option A - + Option B - + Option C - - Submit + + + + Submit + ); } } -ReactDOM.render(, document.getElementById('root')); -``` - -[Try it on CodePen.](https://codepen.io/ericnakagawa/pen/kkAzPO?editors=0010) - -### Form Events - -Event names: +ReactDOM.render( + , + document.getElementById('root') +); ``` -onChange onInput onSubmit -``` + +[Try it on CodePen.](https://codepen.io/gaearon/pen/rrbkWz?editors=0010) diff --git a/docs/reference-events.md b/docs/reference-events.md index b68e65c8..6e275db9 100644 --- a/docs/reference-events.md +++ b/docs/reference-events.md @@ -35,7 +35,7 @@ string type > > As of v0.14, returning `false` from an event handler will no longer stop event propagation. Instead, `e.stopPropagation()` or `e.preventDefault()` should be triggered manually, as appropriate. -### Event pooling +### Event Pooling The `SyntheticEvent` is pooled. This means that the `SyntheticEvent` object will be reused and all properties will be nullified after the event callback has been invoked. This is for performance reasons.