Skip to content

Add more info to FAQ about deps #1815

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

Merged
merged 10 commits into from
Mar 13, 2019
Merged

Add more info to FAQ about deps #1815

merged 10 commits into from
Mar 13, 2019

Conversation

gaearon
Copy link
Member

@gaearon gaearon commented Mar 12, 2019

This addresses the common confusion points around the deps array and optimizing effects, and suggests concrete fixes. It might be too wordy but I figured it's probably worth including.

Open to edits.

useEffect(() => {
function handleStatusChange(status) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved these since it's harder to tell when it's safe, and we should probably just teach people to put them inside effects as a default.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. Functions are generally only called within the effect, so prefer to teach this as the default. As a result a value and not a function will be the effect's dependency, which is slightly easier to understand for beginners.

@reactjs-bot
Copy link

reactjs-bot commented Mar 12, 2019

Deploy preview for reactjs ready!

Built with commit 7639a38

https://deploy-preview-1815--reactjs.netlify.com

@@ -362,6 +365,44 @@ It's possible that in the future React will provide a `usePrevious` Hook out of

See also [the recommended pattern for derived state](#how-do-i-implement-getderivedstatefromprops).

### Why am I seeing stale props or state inside my function? {#why-am-i-seeing-stale-props-or-state-inside-my-function}

Any function inside a component, including event handlers and effects, “sees” the props and state from the render it was defined in. For example, consider code like this:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few suggestions.

  • "sees" is clear enough for me, but due to the quotes maybe a little imprecise.
  • Functions are defined once, but are potentially created multiple times (during renders).
Suggested change
Any function inside a component, including event handlers and effects, sees the props and state from the render it was defined in. For example, consider code like this:
Any function inside a component, including event handlers and effects, contain ("sees") the props and state from the render it was created in. For example, consider code like this:

Copy link
Member

@sophiebits sophiebits left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a couple comments, will review again later…

>
>If you want to run an effect and clean it up only once (on mount and unmount), you can pass an empty array (`[]`) as a second argument. This tells React that your effect doesn't depend on *any* values from props or state, so it never needs to re-run. This isn't handled as a special case -- it follows directly from how the inputs array always works. While passing `[]` is closer to the familiar `componentDidMount` and `componentWillUnmount` mental model, we suggest not making it a habit because it often leads to bugs, [as discussed above](#explanation-why-effects-run-on-each-update). Don't forget that React defers running `useEffect` until after the browser has painted, so doing extra work is less of a problem.
>We provide an [`exhaustive-deps`](https://github.com/facebook/react/issues/14920) ESLint rule as a part of the [`eslint-plugin-react-hooks`](https://www.npmjs.com/package/eslint-plugin-react-hooks#installation) package. It warns when dependencies are specified incorrectly and suggests a fix.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We recommend using the … as part of our …

```js
useEffect(() => {
doSomething();
}, []); // 🔴 This is not safe
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you change this example so that it clearly comes from props and state? Since it is safe to call global functions.

Maybe by showing

  function doSomething() {
    console.log(someProp);
  }

in component scope.


Let's see why this matters.

If you specify a [list of dependencies](/docs/hooks-reference.html#conditionally-firing-an-effect) as the last argument to `useEffect`, `useMemo`, `useCallback`, or `useImperativeHandle`, it must include all values used inside that participate in the React data flow. That includes props, state, or anything derived from them.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

props, state, and anything derived from them.

@gaearon gaearon merged commit 2cd4d0c into reactjs:master Mar 13, 2019
@gaearon gaearon deleted the deps-stuff branch March 13, 2019 13:59
@gaearon
Copy link
Member Author

gaearon commented Mar 13, 2019

I'll get this in for now. I'd love if someone can figure out a way to make it shorter but at least it's in the docs now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants