diff --git a/docs/events.html b/docs/events.html index a9bc77d00f..ca0c1e10c4 100644 --- a/docs/events.html +++ b/docs/events.html @@ -103,7 +103,7 @@
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.
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.
As such, you cannot access the event in an asynchronous way.
Form components such as <input>, <textarea>, and <option> 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:
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.
render() {
- return <input type="text" value="Hello!" />;
+ return (
+ <input
+ type="text"
+ value="Hello!" />
+ );
}
User input has no effect on the rendered element because React has declared the value to be "Hello!". To update the value in response to user input, you would use the onChange event:
+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 input:
class Form extends React.Component {
constructor(props) {
super(props);
- this.state = {value: ""};
+ this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
- this.setState({value: event.target.value});
- }
+ this.setState({value: event.target.value});
+ }
handleSubmit(event) {
- alert("Text field value is: '" + this.state.value + "'");
+ alert('Text field value is: ' + this.state.value);
}
render() {
@@ -116,28 +122,44 @@
<div>
<input type="text"
placeholder="Hello!"
- value={this.state.value}
- onChange={this.handleChange} />
- <button onClick={this.handleSubmit}>Submit</button>
+ value={this.state.value}
+ onChange={this.handleChange} />
+ <button onClick={this.handleSubmit}>
+ Submit
+ </button>
</div>
);
}
}
-ReactDOM.render(<Form />, document.getElementById('root'));
+ReactDOM.render(
+ <Form />,
+ document.getElementById('root')
+);
In this example, we are accepting the value provided by the user and updating the value prop of the <input> component. This pattern makes it easy to implement interfaces that respond to or validate user interactions. For example:
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.
-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.
Controlled components also let us reset inputs to arbitrary values by setting the state:
+ handleClearClick() {
+ this.setState({
+ value: ''
+ });
+ }
+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.
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 <input> control with an empty value. Any user input will be immediately reflected by the rendered element.
If you wanted to listen to updates to the value, you could use the onChange event just like you can with controlled components.
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.
class Form extends React.Component {
constructor(props) {
super(props);
- this.state = {value: ""};
+ this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
+ // Note: with uncontrolled inputs, you don't
+ // have to put the value in the state.
this.setState({value: event.target.value});
}
handleSubmit(event) {
- alert("Text field value is: '" + this.state.value + "'");
+ alert('Text field value is: ' + this.state.value);
}
render() {
return (
<div>
- <input type="text"
+ <input
+ type="text"
placeholder="Hello!"
- value={this.state.value}
- onChange={this.handleChange} />
- <button onClick={this.handleSubmit}>Submit</button>
+ onChange={this.handleChange} />
+ <button onClick={this.handleSubmit}>
+ Submit
+ </button>
</div>
);
}
}
-ReactDOM.render(<Form />, document.getElementById('root'));
+ReactDOM.render(
+ <Form />,
+ document.getElementById('root')
+);
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, an advanced feature discussed later.
To initialize an uncontrolled component with a non-empty value, you can supply a defaultValue prop.
render() {
@@ -210,7 +241,7 @@
Note:
-For <input> and <textarea>, onChange should generally used instead of — the DOM's built-in oninput event handler.
+For <input> and <textarea>, onChange should generally be used instead of the DOM's built-in oninput event handler.
Advanced Topics #
Why Controlled Components? #
Using form components such as <input> in React presents a challenge that is absent when writing traditional form HTML. For example, in HTML:
@@ -226,7 +257,7 @@
Since this method describes the view at any point in time, the value of the text input should always be Untitled.
Why Textarea Value? #
In HTML, the value of <textarea> is usually set using its children:
- <!-- antipattern: DO NOT DO THIS! -->
+ <!-- Don't do this in React. -->
<textarea name="description">This is the description.</textarea>
For HTML, this easily allows developers to supply multiline values. However, since React is JavaScript, we do not have string limitations and can use \n if we want newlines. In a world where we have value and defaultValue, it is ambiguous what role children play. For this reason, you should not use children when setting <textarea> values:
@@ -234,9 +265,9 @@
If you do decide to use children, they will behave like defaultValue.
Why Select Value? #
-The selected <option> in an HTML <select> is normally specified through that option's selected attribute. In React, in order to make components easier to manipulate, the following format is adopted instead:
- <select value="B">
- <option value="A">Apple</option>
+The selected <option> in an HTML <select> is normally specified through that option's selected attribute. In React we assign the select component a specific value by passing a value prop:
+ <select value="B">
+ <option value="A">Apple</option>
<option value="B">Banana</option>
<option value="C">Cranberry</option>
</select>
@@ -248,53 +279,62 @@
You can pass an array into the value attribute, allowing you to select multiple options in a select tag: <select multiple={true} value={['B', 'C']}>.
-Imperative operations #
+Imperative Operations #
If you need to imperatively perform an operation, you have to obtain a reference to the DOM node.
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 Text Input #
class Form extends React.Component {
+Examples #
Controlled Input #
class Form extends React.Component {
constructor(props) {
super(props);
- this.state = {value: ""};
+ this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
- this.setState({value: event.target.value});
- }
+ this.setState({value: event.target.value});
+ }
handleSubmit(event) {
- alert("Text field value is: '" + this.state.value + "'");
+ alert('Text field value is: ' + this.state.value);
}
render() {
return (
<div>
- <input type="text" placeholder="edit me"
- value={this.state.value} onChange={this.handleChange} />
- <button onClick={this.handleSubmit}>Submit</button>
+ <input
+ type="text"
+ placeholder="edit me"
+ value={this.state.value}
+ onChange={this.handleChange}
+ />
+ <button onClick={this.handleSubmit}>
+ Submit
+ </button>
</div>
);
}
}
-ReactDOM.render(<Form />, document.getElementById('root'));
+ReactDOM.render(
+ <Form />,
+ document.getElementById('root')
+);
-
-Basic Textarea #
class Form extends React.Component {
+
+Controlled Textarea #
class Form extends React.Component {
constructor(props) {
super(props);
- this.state = {value: ""};
+ this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
- this.setState({value: event.target.value});
- }
+ this.setState({value: event.target.value});
+ }
handleSubmit(event) {
- alert("Textarea value is: '" + this.state.value + "'");
+ alert('Textarea value is: ' + this.state.value);
}
render() {
@@ -302,55 +342,66 @@ For instance, if you want to imperatively submit a form, one approach would be t
<div>
<textarea
name="description"
- value={this.state.value}
- onChange={this.handleChange}
- />
- <button onClick={this.handleSubmit}>Submit</button>
+ value={this.state.value}
+ onChange={this.handleChange}
+ />
+ <br />
+ <button onClick={this.handleSubmit}>
+ Submit
+ </button>
</div>
);
}
}
-ReactDOM.render(<Form />, document.getElementById('root'));
+ReactDOM.render(
+ <Form />,
+ document.getElementById('root')
+);
-
-Basic Select #
class Form extends React.Component {
+
+Controlled Select #
class Form extends React.Component {
constructor(props) {
super(props);
- this.state = {value: "B"};
+ this.state = {value: 'B'};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
- this.setState({value: event.target.value});
- }
+ this.setState({value: event.target.value});
+ }
handleSubmit(event) {
- alert("Select value is: '" + this.state.value + "'");
+ alert('Select value is: ' + this.state.value);
}
render() {
return (
<div>
- <select value={this.state.value} onChange={this.handleChange}>
- <option value="A">Apple</option>
+ <select value={this.state.value} onChange={this.handleChange}>
+ <option value="A">Apple</option>
<option value="B">Banana</option>
<option value="C">Cranberry</option>
</select>
- <button onClick={this.handleSubmit}>Submit</button>
+ <button onClick={this.handleSubmit}>
+ Submit
+ </button>
</div>
);
}
}
-ReactDOM.render(<Form />, document.getElementById('root'));
+ReactDOM.render(
+ <Form />,
+ document.getElementById('root')
+);
-
-Basic Radio Button #
class Form extends React.Component {
+
+Uncontrolled Radio Button #
class Form extends React.Component {
constructor(props) {
super(props);
- this.state = {value: "B"};
+ this.state = {value: 'B'};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
@@ -360,67 +411,128 @@ For instance, if you want to imperatively submit a form, one approach would be t
}
handleSubmit(event) {
- alert("Radio button value is: '" + this.state.value + "'");
+ alert('Radio button value is: ' + this.state.value);
}
render() {
return (
<div>
- <input type="radio" name="choice" value="A" onChange={this.handleChange} /> Option A<br />
- <input type="radio" name="choice" value="B" onChange={this.handleChange} defaultChecked={true} /> Option B<br />
- <input type="radio" name="choice" value="C" onChange={this.handleChange} /> Option C<br />
+ <label>
+ <input
+ type="radio"
+ name="choice"
+ value="A"
+ onChange={this.handleChange} />
+ Option A
+ </label>
<br />
- <button onClick={this.handleSubmit}>Submit</button>
+ <label>
+ <input
+ type="radio"
+ name="choice"
+ value="B"
+ onChange={this.handleChange}
+ defaultChecked={true} />
+ Option B
+ </label>
+ <br />
+ <label>
+ <input
+ type="radio"
+ name="choice"
+ value="C"
+ onChange={this.handleChange} />
+ Option C
+ </label>
+ <br />
+ <br />
+ <button onClick={this.handleSubmit}>
+ Submit
+ </button>
</div>
);
}
}
-ReactDOM.render(<Form />, document.getElementById('root'));
+ReactDOM.render(
+ <Form />,
+ document.getElementById('root')
+);
-
-Basic Checkbox #
class Form extends React.Component {
+
+Uncontrolled Checkbox #
class Form extends React.Component {
constructor(props) {
super(props);
- this.state = {checked: ["B"]};
+ this.state = {checked: {'A': false, 'B': true, 'C': false}};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
- let val = event.target.value;
- let checked = this.state.checked.slice(); // copy
- if(checked.includes(val)) {
- checked.splice(checked.indexOf(val), 1);
+ 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.push(val);
- }
- this.setState({checked: checked})
+ checked[value] = false;
+ };
+ this.setState({checked});
}
handleSubmit(event) {
- alert("Boxes checked are: '" + this.state.checked + "'");
+ alert('Boxes checked: ' +
+ (this.state.checked.A ? 'A ' : '') +
+ (this.state.checked.B ? 'B ' : '') +
+ (this.state.checked.C ? 'C' : '')
+ );
}
render() {
return (
<div>
- <input type="checkbox" value="A" onChange={this.handleChange} /> Option A<br />
- <input type="checkbox" value="B" onChange={this.handleChange} defaultChecked={true} /> Option B<br />
- <input type="checkbox" value="C" onChange={this.handleChange} /> Option C<br />
+ <label>
+ <input
+ type="checkbox"
+ value="A"
+ onChange={this.handleChange} />
+ Option A
+ </label>
<br />
- <button onClick={this.handleSubmit}>Submit</button>
+ <label>
+ <input
+ type="checkbox"
+ value="B"
+ onChange={this.handleChange}
+ defaultChecked={true} />
+ Option B
+ </label>
+ <br />
+ <label>
+ <input
+ type="checkbox"
+ value="C"
+ onChange={this.handleChange} />
+ Option C
+ </label>
+ <br />
+ <br />
+ <button onClick={this.handleSubmit}>
+ Submit
+ </button>
</div>
);
}
}
-ReactDOM.render(<Form />, document.getElementById('root'));
-
-
-Form Events #
-Event names:
-onChange onInput onSubmit
+
+ReactDOM.render(
+ <Form />,
+ document.getElementById('root')
+);
+
+
diff --git a/docs/lists-and-keys.html b/docs/lists-and-keys.html
index 3c741adb2d..eeec10a87e 100644
--- a/docs/lists-and-keys.html
+++ b/docs/lists-and-keys.html
@@ -191,7 +191,7 @@
function NumberList(props) {
const numbers = props.numbers;
- const listItems = numbers.map((item) =>
+ const listItems = numbers.map((number) =>
// Wrong! The key should have been specified here:
<ListItem value={number} />
);
diff --git a/docs/reconciliation.html b/docs/reconciliation.html
index 568398b5f0..ef222c3e1e 100644
--- a/docs/reconciliation.html
+++ b/docs/reconciliation.html
@@ -93,13 +93,13 @@
In practice, these assumptions are valid for almost all practical use cases.
The Diffing Algorithm #
-When diffing two trees, React first compares the the two root elements. The behavior is different depending on the types of the root elements.
+When diffing two trees, React first compares the two root elements. The behavior is different depending on the types of the root elements.
Elements Of Different Types #
Whenever the root elements have different types, React will tear down the old tree and build the new tree from scratch. Going from <a> to <img>, or from <Article> to <Comment>, or from <Button> to <div> - any of those will lead to a full rebuild.
When tearing down a tree, old DOM nodes are destroyed. Component instances receive componentWillUnmount(). When building up a new tree, new DOM nodes are inserted into the DOM. Component instances receive componentWillMount() and then componentDidMount(). Any state associated with the old tree is lost.
-Any componts below the root will also get unmounted and have their state destroyed. For example, when diffing:
+Any components below the root will also get unmounted and have their state destroyed. For example, when diffing:
<div>
<Counter />
</div>
diff --git a/docs/test-utils.html b/docs/test-utils.html
index 5528dee25d..574ff14bd0 100644
--- a/docs/test-utils.html
+++ b/docs/test-utils.html
@@ -171,9 +171,9 @@
-renderIntoDocument() #
renderIntoDocument(instance)
+renderIntoDocument() #
renderIntoDocument(element)
-Render a component into a detached DOM node in the document. This function requires a DOM.
+Render a React element into a detached DOM node in the document. This function requires a DOM.
Note:
diff --git a/tutorial/tutorial.html b/tutorial/tutorial.html
index 0258217083..07821ea20c 100644
--- a/tutorial/tutorial.html
+++ b/tutorial/tutorial.html
@@ -458,8 +458,8 @@
Its handleClick can push a new entry onto the stack by concatenating the new history entry to make a new history array:
handleClick(i) {
- var history = this.state.history;
- var current = history[history.length - 1];
+ const history = this.state.history;
+ const current = history[history.length - 1];
const squares = current.squares.slice();
if (calculateWinner(squares) || squares[i]) {
return;