diff --git a/content/docs/faq-state.md b/content/docs/faq-state.md index f7a467a5..3cc3d267 100644 --- a/content/docs/faq-state.md +++ b/content/docs/faq-state.md @@ -6,13 +6,13 @@ layout: docs category: FAQ --- -### What does setState do? +### What does `setState` do? `setState()` schedules an update to a component's `state` object. When state changes, the component responds by re-rendering. -### What is the difference between state and props? +### What is the difference between `state` and `props`? -[`props`](/docs/components-and-props.html) (short for "properties") and [`state`](/docs/state-and-lifecycle.html) are both just JavaScript objects that trigger a re-render when changed. While both hold information that influences the output of render, they are different in one important way: `props` get passed to the component (similar to function parameters) whereas `state` is managed within the component (similar to variables declared within a function). +[`props`](/docs/components-and-props.html) (short for "properties") and [`state`](/docs/state-and-lifecycle.html) are both plain JavaScript objects. While both hold information that influences the output of render, they are different in one important way: `props` get passed *to* the component (similar to function parameters) whereas `state` is managed *within* the component (similar to variables declared within a function). Here are some good resources for further reading on when to use `props` vs `state`: * [Props vs State](https://github.com/uberVU/react-guide/blob/master/props-vs-state.md) @@ -20,9 +20,11 @@ Here are some good resources for further reading on when to use `props` vs `stat ### Why is `setState` giving me the wrong value? +In React, both `this.props` and `this.state` represent the *rendered* values, i.e. what's currently on the screen. + Calls to `setState` are asynchronous - don't rely on `this.state` to reflect the new value immediately after calling `setState`. Pass an updater function instead of an object if you need compute values based on the current state (see below for details). -Example of code that will not behave as expected: +Example of code that will *not* behave as expected: ```jsx incrementCount() { @@ -31,9 +33,17 @@ incrementCount() { } handleSomething() { - // this.state.count is 1, then we do this: + // Let's say `this.state.count` starts at 0. + this.incrementCount(); + this.incrementCount(); this.incrementCount(); - this.incrementCount(); // state wasn't updated yet, so this sets 2 not 3 + // When React re-renders the component, `this.state.count` will be 1, but you expected 3. + + // This is because `incrementCount()` function above reads from `this.state.count`, + // but React doesn't update `this.state.count` until the component is re-rendered. + // So `incrementCount()` ends up reading `this.state.count` as 0 every time, and sets it to 1. + + // The fix is described below! } ``` @@ -41,28 +51,54 @@ See below for how to fix this problem. ### How do I update state with values that depend on the current state? -Pass a function instead of an object to setState to ensure the call always uses the most updated version of state (see below). +Pass a function instead of an object to `setState` to ensure the call always uses the most updated version of state (see below). -### What is the difference between passing an object or a function in setState? +### What is the difference between passing an object or a function in `setState`? Passing an update function allows you to access the current state value inside the updater. Since `setState` calls are batched, this lets you chain updates and ensure they build on top of each other instead of conflicting: ```jsx incrementCount() { this.setState((prevState) => { + // Important: read `prevState` instead of `this.state` when updating. return {count: prevState.count + 1} }); } handleSomething() { - // this.state.count is 1, then we do this: + // Let's say `this.state.count` starts at 0. this.incrementCount(); - this.incrementCount(); // count is now 3 + this.incrementCount(); + this.incrementCount(); + + // If you read `this.state.count` now, it would still be 0. + // But when React re-renders the component, it will be 3. } ``` [Learn more about setState](/docs/react-component.html#setstate) +### When is `setState` asynchronous? + +Currently, `setState` is asynchronous inside event handlers. + +This ensures, for example, that if both `Parent` and `Child` call `setState` during a click event, `Child` isn't re-rendered twice. Instead, React "flushes" the state updates at the end of the browser event. This results in significant performance improvements in larger apps. + +This is an implementation detail so avoid relying on it directly. In the future versions, React will batch updates by default in more cases. + +### Why doesn't React update `this.state` synchronously? + +As explained in the previous section, React intentionally "waits" until all components call `setState()` in their event handlers before starting to re-render. This boosts performance by avoiding unnecessary re-renders. + +However, you might still be wondering why React doesn't just update `this.state` immediately without re-rendering. + +There are two main reasons: + +* This would break the consistency between `props` and `state`, causing issues that are very hard to debug. +* This would make some of the new features we're working on impossible to implement. + +This [GitHub comment](https://github.com/facebook/react/issues/11527#issuecomment-360199710) dives deep into the specific examples. + ### Should I use a state management library like Redux or MobX? [Maybe.](http://redux.js.org/docs/faq/General.html#general-when-to-use)