-
Notifications
You must be signed in to change notification settings - Fork 47k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Docs: Clarification of setState() behavior #9329
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -230,34 +230,53 @@ componentWillUnmount() | |
### `setState()` | ||
|
||
```javascript | ||
setState(nextState, callback) | ||
setState(updater, [callback]) | ||
``` | ||
|
||
Performs a shallow merge of nextState into current state. This is the primary method you use to trigger UI updates from event handlers and server request callbacks. | ||
`setState()` is an asynchronous method which enqueues changes to be made to the state during the next update cycle. This is the primary method you use to trigger UI updates in response to UI event handlers, server responses, etc... | ||
|
||
The first argument can be an object (containing zero or more keys to update) or a function (of state and props) that returns an object containing keys to update. | ||
`setState()` does not immediately mutate `this.state` but creates a pending state transition. Accessing `this.state` after calling this method can potentially return the previous state, rather than the state after enqueued updates have been applied. This is a common source of bugs in React applications. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It could also return a future state that hasn't flushed yet, or a state that was aborted completely.
Source? This seems overly alarmist. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know this from mentoring students & product teams who are making the switch to React. I saw two examples yesterday. See setState Gate. Further evidence is available by searching for setState on Stack Overflow (there are MANY more examples of confused setState users on Stack Overflow). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
That bit is just a slight rephrase of the current doc, which says "potentially return the existing value". There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe
? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is better, but I'm concerned that it implies that What I'd like to write is
but this might be too prescriptive. Because again, this isn't really an issue in sync mode, only with async. And we'll likely have to come up with a new API for async mode, anyway, at which point this Maybe this is a good way to split the difference:
|
||
|
||
Here is the simple object usage: | ||
There is no guarantee of synchronous operation of calls to `setState`. | ||
|
||
`setState()` will always lead to a re-render unless `shouldComponentUpdate()` returns `false`. If mutable objects are being used and conditional rendering logic cannot be implemented in `shouldComponentUpdate()`, calling `setState()` only when the new state differs from the previous state will avoid unnecessary re-renders. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This part feels a little too opaque for beginners
What does conditional rendering logic have to do with
Don't you only get the new state by calling There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I didn't write this part. It's already in the docs. Maybe cleanup of that wording could happen in a separate PR. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, the diff made it look like you did. It would be nice to simplify this here or in another PR 👍 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree. I wasn't sure what to do with it, so I left it alone for now. =) |
||
|
||
The first argument is an updater function with the signature: | ||
|
||
```javascript | ||
this.setState({mykey: 'my new value'}); | ||
(prevState, props) => nextState | ||
``` | ||
|
||
It's also possible to pass a function with the signature `function(state, props) => newState`. This enqueues an atomic update that consults the previous value of state and props before setting any values. For instance, suppose we wanted to increment a value in state by `props.step`: | ||
`prevState` is a reference to the previous state. It should not be directly mutated. Instead, changes should be represented by building a `nextState` based on the input from `prevState` and `props`. For instance, suppose we wanted to increment a value in state by `props.step`: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Maybe change to
As it's unclear what There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point. =) |
||
|
||
```javascript | ||
this.setState((prevState, props) => { | ||
return {myInteger: prevState.myInteger + props.step}; | ||
}); | ||
``` | ||
|
||
The second parameter is an optional callback function that will be executed once `setState` is completed and the component is re-rendered. Generally we recommend using `componentDidUpdate()` for such logic instead. | ||
The second parameter to `setState()` is an optional callback function that will be executed once `setState` is completed and the component is re-rendered. Generally we recommend using `componentDidUpdate()` for such logic instead. | ||
|
||
You may optionally pass an object as the first argument to `setState()` instead of a function: | ||
|
||
```javascript | ||
setState(stateChange, callback) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we use an object literal instead so it's a little more familiar? Maybe use the same example above that updates setState({ myInteger: this.state.myInteger + this.props.step }) That could also serve as an example of a situation where the setState callback is preferred, as There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is intended to show the signature, not an example, but you make a good point that an example would be helpful. |
||
``` | ||
|
||
This performs a shallow merge of `stateChange` into the new state. This form of `setState()` is also asynchronous, and multiple calls during the same cycle may be batched together, which will result in the equivalent of: | ||
|
||
`setState()` does not immediately mutate `this.state` but creates a pending state transition. Accessing `this.state` after calling this method can potentially return the existing value. | ||
```javaScript | ||
Object.assign( | ||
previousState, | ||
stateChange1, | ||
stateChange2, | ||
... | ||
) | ||
``` | ||
|
||
There is no guarantee of synchronous operation of calls to `setState` and calls may be batched for performance gains. | ||
Subsequent calls may override values from previous calls. If the next state depends on the previous state, we recommend using the updater function form, instead. | ||
|
||
`setState()` will always lead to a re-render unless `shouldComponentUpdate()` returns `false`. If mutable objects are being used and conditional rendering logic cannot be implemented in `shouldComponentUpdate()`, calling `setState()` only when the new state differs from the previous state will avoid unnecessary re-renders. | ||
For more detail, see the [State and Lifecycle guide](/react/docs/state-and-lifecycle.html). | ||
|
||
* * * | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can probably get away with removing UI here