From 439584a6f4070f34a92dd62ae1217d4009d8bcdd Mon Sep 17 00:00:00 2001 From: Nat Alison Date: Mon, 11 Mar 2019 12:48:20 -0700 Subject: [PATCH 01/16] Update languages.yml (#1808) * Brazilian Portuguese is complete! * Update status of Hebrew, Polish, German --- content/languages.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/content/languages.yml b/content/languages.yml index ff0be2c1d..d34224dda 100644 --- a/content/languages.yml +++ b/content/languages.yml @@ -26,7 +26,7 @@ - name: German translated_name: Deutsch code: de - status: 0 + status: 1 - name: Greek translated_name: Ελληνικά code: el @@ -50,7 +50,7 @@ - name: Hebrew translated_name: עברית code: he - status: 0 + status: 1 - name: Hindi translated_name: हिन्दी code: hi @@ -102,11 +102,11 @@ - name: Polish translated_name: Polski code: pl - status: 0 + status: 1 - name: Portuguese (Brazil) translated_name: Português do Brasil code: pt-br - status: 1 + status: 2 - name: Portuguese (Portugal) translated_name: Português europeu code: pt-pt From d827d5958a7d01b278b5e6e3428d6d6676ae7dd0 Mon Sep 17 00:00:00 2001 From: Nat Alison Date: Wed, 13 Mar 2019 03:34:06 -0700 Subject: [PATCH 02/16] Update languages.yml (#1820) * Russian is complete! * Move some other languages up --- content/languages.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/content/languages.yml b/content/languages.yml index d34224dda..5e0958260 100644 --- a/content/languages.yml +++ b/content/languages.yml @@ -78,7 +78,7 @@ - name: Korean translated_name: 한국어 code: ko - status: 0 + status: 1 - name: Kurdish translated_name: کوردی‎ code: ku @@ -118,7 +118,7 @@ - name: Russian translated_name: Русский code: ru - status: 1 + status: 2 - name: Sinhala translated_name: සිංහල code: si @@ -137,7 +137,7 @@ - name: Turkish translated_name: Türkçe code: tr - status: 0 + status: 1 - name: Ukrainian translated_name: Українська code: uk From 2cd4d0cf5ddadf90446b3a5038a9bc4875151355 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Wed, 13 Mar 2019 13:59:42 +0000 Subject: [PATCH 03/16] Add more info to FAQ about deps (#1815) * Add more info to FAQ about deps * Update content/docs/hooks-faq.md Co-Authored-By: gaearon * Update content/docs/hooks-faq.md Co-Authored-By: gaearon * Update content/docs/hooks-faq.md Co-Authored-By: gaearon * Update content/docs/hooks-faq.md Co-Authored-By: gaearon * Update content/docs/hooks-effect.md Co-Authored-By: gaearon * tweaks * tweak --- content/docs/hooks-custom.md | 24 ++-- content/docs/hooks-effect.md | 37 +++-- content/docs/hooks-faq.md | 248 +++++++++++++++++++++++++++++++- content/docs/hooks-reference.md | 41 ++++-- content/docs/hooks-rules.md | 3 +- 5 files changed, 316 insertions(+), 37 deletions(-) diff --git a/content/docs/hooks-custom.md b/content/docs/hooks-custom.md index ac9dad6da..a252ac3f3 100644 --- a/content/docs/hooks-custom.md +++ b/content/docs/hooks-custom.md @@ -18,11 +18,11 @@ import React, { useState, useEffect } from 'react'; function FriendStatus(props) { const [isOnline, setIsOnline] = useState(null); - function handleStatusChange(status) { - setIsOnline(status.isOnline); - } - useEffect(() => { + function handleStatusChange(status) { + setIsOnline(status.isOnline); + } + ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange); return () => { ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange); @@ -44,11 +44,11 @@ import React, { useState, useEffect } from 'react'; function FriendListItem(props) { const [isOnline, setIsOnline] = useState(null); - function handleStatusChange(status) { - setIsOnline(status.isOnline); - } - useEffect(() => { + function handleStatusChange(status) { + setIsOnline(status.isOnline); + } + ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange); return () => { ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange); @@ -79,11 +79,11 @@ import React, { useState, useEffect } from 'react'; function useFriendStatus(friendID) { const [isOnline, setIsOnline] = useState(null); - function handleStatusChange(status) { - setIsOnline(status.isOnline); - } - useEffect(() => { + function handleStatusChange(status) { + setIsOnline(status.isOnline); + } + ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange); return () => { ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange); diff --git a/content/docs/hooks-effect.md b/content/docs/hooks-effect.md index 64b32476e..fd7d89592 100644 --- a/content/docs/hooks-effect.md +++ b/content/docs/hooks-effect.md @@ -198,17 +198,17 @@ Let's see how we could write this component with Hooks. You might be thinking that we'd need a separate effect to perform the cleanup. But code for adding and removing a subscription is so tightly related that `useEffect` is designed to keep it together. If your effect returns a function, React will run it when it is time to clean up: -```js{10-16} +```js{6-16} import React, { useState, useEffect } from 'react'; function FriendStatus(props) { const [isOnline, setIsOnline] = useState(null); - function handleStatusChange(status) { - setIsOnline(status.isOnline); - } - useEffect(() => { + function handleStatusChange(status) { + setIsOnline(status.isOnline); + } + ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange); // Specify how to clean up after this effect: return function cleanup() { @@ -237,6 +237,10 @@ We've learned that `useEffect` lets us express different kinds of side effects a ```js useEffect(() => { + function handleStatusChange(status) { + setIsOnline(status.isOnline); + } + ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange); return () => { ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange); @@ -316,15 +320,15 @@ function FriendStatusWithCounter(props) { const [isOnline, setIsOnline] = useState(null); useEffect(() => { + function handleStatusChange(status) { + setIsOnline(status.isOnline); + } + ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange); return () => { ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange); }; }); - - function handleStatusChange(status) { - setIsOnline(status.isOnline); - } // ... } ``` @@ -394,6 +398,7 @@ Now consider the version of this component that uses Hooks: function FriendStatus(props) { // ... useEffect(() => { + // ... ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange); return () => { ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange); @@ -449,8 +454,12 @@ When we render with `count` updated to `6`, React will compare the items in the This also works for effects that have a cleanup phase: -```js{6} +```js{10} useEffect(() => { + function handleStatusChange(status) { + setIsOnline(status.isOnline); + } + ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange); return () => { ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange); @@ -462,9 +471,13 @@ In the future, the second argument might get added automatically by a build-time >Note > ->If you use this optimization, make sure the array includes **any values from the outer scope that change over time and that are used by the effect**. Otherwise, your code will reference stale values from previous renders. We'll also discuss other optimization options in the [Hooks API reference](/docs/hooks-reference.html). +>If you use this optimization, make sure the array includes **all values from the component scope (such as props and state) that change over time and that are used by the effect**. Otherwise, your code will reference stale values from previous renders. Learn more about [how to deal with functions](/docs/hooks-faq.html#is-it-safe-to-omit-functions-from-the-list-of-dependencies) and [what to do when the array changes too often](/docs/hooks-faq.html#what-can-i-do-if-my-effect-dependencies-change-too-often). +> +>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. +> +>If you pass an empty array (`[]`), the props and state inside the effect will always have their initial values. While passing `[]` as the second argument is closer to the familiar `componentDidMount` and `componentWillUnmount` mental model, there are usually [better](/docs/hooks-faq.html#is-it-safe-to-omit-functions-from-the-list-of-dependencies) [solutions](/docs/hooks-faq.html#what-can-i-do-if-my-effect-dependencies-change-too-often) to avoid re-running effects too often. Also, don't forget that React defers running `useEffect` until after the browser has painted, so doing extra work is less of a problem. > ->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 recommend using the [`exhaustive-deps`](https://github.com/facebook/react/issues/14920) rule as part of our [`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. ## Next Steps {#next-steps} diff --git a/content/docs/hooks-faq.md b/content/docs/hooks-faq.md index b3b99de90..6145b968d 100644 --- a/content/docs/hooks-faq.md +++ b/content/docs/hooks-faq.md @@ -32,16 +32,20 @@ This page answers some of the frequently asked questions about [Hooks](/docs/hoo * [What exactly do the lint rules enforce?](#what-exactly-do-the-lint-rules-enforce) * **[From Classes to Hooks](#from-classes-to-hooks)** * [How do lifecycle methods correspond to Hooks?](#how-do-lifecycle-methods-correspond-to-hooks) + * [How can I do data fetching with Hooks?](#how-can-i-do-data-fetching-with-hooks) * [Is there something like instance variables?](#is-there-something-like-instance-variables) * [Should I use one or many state variables?](#should-i-use-one-or-many-state-variables) * [Can I run an effect only on updates?](#can-i-run-an-effect-only-on-updates) * [How to get the previous props or state?](#how-to-get-the-previous-props-or-state) + * [Why am I seeing stale props or state inside my function?](#why-am-i-seeing-stale-props-or-state-inside-my-function) * [How do I implement getDerivedStateFromProps?](#how-do-i-implement-getderivedstatefromprops) * [Is there something like forceUpdate?](#is-there-something-like-forceupdate) * [Can I make a ref to a function component?](#can-i-make-a-ref-to-a-function-component) * [What does const [thing, setThing] = useState() mean?](#what-does-const-thing-setthing--usestate-mean) * **[Performance Optimizations](#performance-optimizations)** * [Can I skip an effect on updates?](#can-i-skip-an-effect-on-updates) + * [Is it safe to omit functions from the list of dependencies?](#is-it-safe-to-omit-functions-from-the-list-of-dependencies) + * [What can I do if my effect dependencies change too often?](#what-can-i-do-if-my-effect-dependencies-change-too-often) * [How do I implement shouldComponentUpdate?](#how-do-i-implement-shouldcomponentupdate) * [How to memoize calculations?](#how-to-memoize-calculations) * [How to create expensive objects lazily?](#how-to-create-expensive-objects-lazily) @@ -204,6 +208,10 @@ There are a few more heuristics, and they might change over time as we fine-tune * `componentDidCatch` and `getDerivedStateFromError`: There are no Hook equivalents for these methods yet, but they will be added soon. +### How can I do data fetching with Hooks? + +Check out [this article](https://www.robinwieruch.de/react-hooks-fetch-data/) to learn more about data fetching with Hooks. + ### Is there something like instance variables? {#is-there-something-like-instance-variables} Yes! The [`useRef()`](/docs/hooks-reference.html#useref) Hook isn't just for DOM refs. The "ref" object is a generic container whose `current` property is mutable and can hold any value, similar to an instance property on a class. @@ -362,6 +370,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 created in. For example, consider code like this: + +```js +function Example() { + const [count, setCount] = useState(0); + + function handleAlertClick() { + setTimeout(() => { + alert('You clicked on: ' + count); + }, 3000); + } + + return ( +
+

You clicked {count} times

+ + +
+ ); +} +``` + +If you first click "Show alert" and then increment the counter, the alert will show the `count` variable **at the time you clicked the "Show alert" button**. This prevents bugs caused by the code assuming props and state don't change. + +If you intentionally want to read the *latest* state from some asynchronous callback, you could keep it in [a ref](/docs/hooks-faq.html#is-there-something-like-instance-variables), mutate it, and read from it. + +Finally, another possible reason you're seeing stale props or state is if you use the "dependency array" optimization but didn't correctly specify all the dependencies. For example, if an effect specifies `[]` as the second argument but reads `someProp` inside, it will keep "seeing" the initial value of `someProp`. The solution is to either remove the dependency array, or to fix it. Here's [how you can deal with functions](#is-it-safe-to-omit-functions-from-the-list-of-dependencies), and here's [other common strategies](#what-can-i-do-if-my-effect-dependencies-change-too-often) to run effects less often without incorrectly skipping dependencies. + +>Note +> +>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. + ### How do I implement `getDerivedStateFromProps`? {#how-do-i-implement-getderivedstatefromprops} While you probably [don't need it](/blog/2018/06/07/you-probably-dont-need-derived-state.html), in rare cases that you do (such as implementing a `` component), you can update the state right during rendering. React will re-run the component with updated state immediately after exiting the first render so it wouldn't be expensive. @@ -416,6 +462,207 @@ If you're not familiar with this syntax, check out the [explanation](/docs/hooks Yes. See [conditionally firing an effect](/docs/hooks-reference.html#conditionally-firing-an-effect). Note that forgetting to handle updates often [introduces bugs](/docs/hooks-effect.html#explanation-why-effects-run-on-each-update), which is why this isn't the default behavior. +### Is it safe to omit functions from the list of dependencies? {#is-it-safe-to-omit-functions-from-the-list-of-dependencies} + +Generally speaking, no. + +```js{3,8} +function Example() { + function doSomething() { + console.log(someProp); + } + + useEffect(() => { + doSomething(); + }, []); // 🔴 This is not safe (it calls `doSomething` which uses `someProp`) +} +``` + +It's difficult to remember which props or state are used by functions outside of the effect. This is why **usually you'll want to declare functions needed by an effect *inside* of it.** Then it's easy to see what values from the component scope that effect depends on: + +```js{4,8} +function Example() { + useEffect(() => { + function doSomething() { + console.log(someProp); + } + + doSomething(); + }, [someProp]); // ✅ OK (our effect only uses `someProp`) +} +``` + +If after that we still don't use any values from the component scope, it's safe to specify `[]`: + +```js{7} +useEffect(() => { + function doSomething() { + console.log('hello'); + } + + doSomething(); +}, []); // ✅ OK in this example because we don't use *any* values from component scope +``` + +Depending on your use case, there are a few more options described below. + +>Note +> +>We provide the [`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 help you find components that don't handle updates consistently. + +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, and anything derived from them. + +It is **only** safe to omit a function from the dependency list if nothing in it (or the functions called by it) references props, state, or values derived from them. This example has a bug: + +```js{5,12} +function ProductPage({ productId }) { + const [product, setProduct] = useState(null); + + async function fetchProduct() { + const response = await fetch('http://myapi/product' + productId); // Uses productId prop + const json = await response.json(); + setProduct(json); + } + + useEffect(() => { + fetchProduct(); + }, []); // 🔴 Invalid because `fetchProduct` uses `productId` + // ... +} +``` + +**The recommended fix is to move that function _inside_ of your effect**. That makes it easy to see which props or state your effect uses, and to ensure they're all declared: + +```js{5-10,13} +function ProductPage({ productId }) { + const [product, setProduct] = useState(null); + + useEffect(() => { + // By moving this function inside the effect, we can clearly see the values it uses. + async function fetchProduct() { + const response = await fetch('http://myapi/product' + productId); + const json = await response.json(); + setProduct(json); + } + + fetchProduct(); + }, [productId]); // ✅ Valid because our effect only uses productId + // ... +} +``` + +This also allows you to handle out-of-order responses with a local variable inside the effect: + +```js{2,6,8} + useEffect(() => { + let ignore = false; + async function fetchProduct() { + const response = await fetch('http://myapi/product/' + productId); + const json = await response.json(); + if (!ignore) setProduct(json); + } + return () => { ignore = true }; + }, [productId]); +``` + +We moved the function inside the effect so it doesn't need to be in its dependency list. + +>Tip +> +>Check out [this article](https://www.robinwieruch.de/react-hooks-fetch-data/) to learn more about data fetching with Hooks. + +**If for some reason you _can't_ move a function inside an effect, there are a few more options:** + +* **You can try moving that function outside of your component**. In that case, the function is guaranteed to not reference any props or state, and also doesn't need to be in the list of dependencies. +* If the function you're calling is a pure computation and is safe to call while rendering, you may **call it outside of the effect instead,** and make the effect depend on the returned value. +* As a last resort, you can **add a function to effect dependencies but _wrap its definition_** into the [`useCallback`](/docs/hooks-reference.html#usecallback) Hook. This ensures it doesn't change on every render unless *its own* dependencies also change: + +```js{2-5} +function ProductPage({ productId }) { + // ✅ Wrap with useCallback to avoid change on every render + const fetchProduct = useCallback(() => { + // ... Does something with productId ... + }, [productId]); // ✅ All useCallback dependencies are specified + + return ; +} + +function ProductDetails({ fetchProduct }) + useEffect(() => { + fetchProduct(); + }, [fetchProduct]); // ✅ All useEffect dependencies are specified + // ... +} +``` + +Note that in the above example we **need** to keep the function in the dependencies list. This ensures that a change in the `productId` prop of `ProductPage` automatically triggers a refetch in the `ProductDetails` component. + +### What can I do if my effect dependencies change too often? + +Sometimes, your effect may be using reading state that changes too often. You might be tempted to omit that state from a list of dependencies, but that usually leads to bugs: + +```js{6,9} +function Counter() { + const [count, setCount] = useState(0); + + useEffect(() => { + const id = setInterval(() => { + setCount(count + 1); // This effect depends on the `count` state + }, 1000); + return () => clearInterval(id); + }, []); // 🔴 Bug: `count` is not specified as a dependency + + return

{count}

; +} +``` + +Specifying `[count]` as a list of dependencies would fix the bug, but would cause the interval to be reset on every change. That may not be desirable. To fix this, we can use the [functional update form of `setState`](/docs/hooks-reference.html#functional-updates). It lets us specify *how* the state needs to change without referencing the *current* state: + +```js{6,9} +function Counter() { + const [count, setCount] = useState(0); + + useEffect(() => { + const id = setInterval(() => { + setCount(c => c + 1); // ✅ This doesn't depend on `count` variable outside + }, 1000); + return () => clearInterval(id); + }, []); // ✅ Our effect doesn't use any variables in the component scope + + return

{count}

; +} +``` + +(The identity of the `setCount` function is guaranteed to be stable so it's safe to omit.) + +In more complex cases (such as if one state depends on another state), try moving the state update logic outside the effect with the [`useReducer` Hook](/docs/hooks-reference.html#usereducer). [This article](https://adamrackis.dev/state-and-use-reducer/) offers an example of how you can do this. **The identity of the `dispatch` function from `useReducer` is always stable** — even if the reducer function is declared inside the component and reads its props. + +As a last resort, if you want to something like `this` in a class, you can [use a ref](/docs/hooks-faq.html#is-there-something-like-instance-variables) to hold a mutable variable. Then you can write and read to it. For example: + +```js{2-6,10-11,16} +function Example(props) { + // Keep latest props in a ref. + let latestProps = useRef(props); + useEffect(() => { + latestProps.current = props; + }); + + useEffect(() => { + function tick() { + // Read latest props at any time + console.log(latestProps.current); + } + + const id = setInterval(tick, 1000); + return () => clearInterval(id); + }, []); // This effect never re-runs +} +``` + +Only do this if you couldn't find a better alternative, as relying on mutation makes components less predictable. If there's a specific pattern that doesn't translate well, [file an issue](https://github.com/facebook/react/issues/new) with a runnable example code and we can try to help. + ### How do I implement `shouldComponentUpdate`? {#how-do-i-implement-shouldcomponentupdate} You can wrap a function component with `React.memo` to shallowly compare its props: @@ -430,7 +677,6 @@ It's not a Hook because it doesn't compose like Hooks do. `React.memo` is equiva `React.memo` doesn't compare state because there is no single state object to compare. But you can make children pure too, or even [optimize individual children with `useMemo`](/docs/hooks-faq.html#how-to-memoize-calculations). - ### How to memoize calculations? {#how-to-memoize-calculations} The [`useMemo`](/docs/hooks-reference.html#usememo) Hook lets you cache calculations between multiple renders by "remembering" the previous computation: diff --git a/content/docs/hooks-reference.md b/content/docs/hooks-reference.md index deeef54cf..4466bc83b 100644 --- a/content/docs/hooks-reference.md +++ b/content/docs/hooks-reference.md @@ -45,6 +45,10 @@ setState(newState); During subsequent re-renders, the first value returned by `useState` will always be the most recent state after applying updates. +>Note +> +>React guarantees that `setState` function identity is stable and won't change on re-renders. This is why it's safe to omit from the `useEffect` or `useCallback` dependency list. + #### Functional updates {#functional-updates} If the new state is computed using the previous state, you can pass a function to `setState`. The function will receive the previous value, and return an updated value. Here's an example of a counter component that uses both forms of `setState`: @@ -133,7 +137,7 @@ Although `useEffect` is deferred until after the browser has painted, it's guara #### Conditionally firing an effect {#conditionally-firing-an-effect} -The default behavior for effects is to fire the effect after every completed render. That way an effect is always recreated if one of its inputs changes. +The default behavior for effects is to fire the effect after every completed render. That way an effect is always recreated if one of its dependencies changes. However, this may be overkill in some cases, like the subscription example from the previous section. We don't need to create a new subscription on every update, only if the `source` props has changed. @@ -153,11 +157,18 @@ useEffect( Now the subscription will only be recreated when `props.source` changes. -Passing in an empty array `[]` of inputs tells React that your effect doesn't depend on any values from the component, so that effect would run only on mount and clean up on unmount; it won't run on updates. - -> Note +>Note +> +>If you use this optimization, make sure the array includes **all values from the component scope (such as props and state) that change over time and that are used by the effect**. Otherwise, your code will reference stale values from previous renders. Learn more about [how to deal with functions](/docs/hooks-faq.html#is-it-safe-to-omit-functions-from-the-list-of-dependencies) and what to do when the [array values change too often](/docs/hooks-faq.html#what-can-i-do-if-my-effect-dependencies-change-too-often). +> +>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 dependencies array always works. > -> The array of inputs is not passed as arguments to the effect function. Conceptually, though, that's what they represent: every value referenced inside the effect function should also appear in the inputs array. In the future, a sufficiently advanced compiler could create this array automatically. +>If you pass an empty array (`[]`), the props and state as inside the effect will always have their initial values. While passing `[]` as the second argument is closer to the familiar `componentDidMount` and `componentWillUnmount` mental model, there are usually [better](/docs/hooks-faq.html#is-it-safe-to-omit-functions-from-the-list-of-dependencies) [solutions](/docs/hooks-faq.html#what-can-i-do-if-my-effect-dependencies-change-too-often) to avoid re-running effects too often. Also, don't forget that React defers running `useEffect` until after the browser has painted, so doing extra work is less of a problem. +> +> +>We recommend using the [`exhaustive-deps`](https://github.com/facebook/react/issues/14920) rule as part of our [`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. + +The array of dependencies is not passed as arguments to the effect function. Conceptually, though, that's what they represent: every value referenced inside the effect function should also appear in the dependencies array. In the future, a sufficiently advanced compiler could create this array automatically. ### `useContext` {#usecontext} @@ -211,6 +222,10 @@ function Counter({initialState}) { } ``` +>Note +> +>React guarantees that `dispatch` function identity is stable and won't change on re-renders. This is why it's safe to omit from the `useEffect` or `useCallback` dependency list. + #### Specifying the initial state {#specifying-the-initial-state} There’s two different ways to initialize `useReducer` state. You may choose either one depending on the use case. The simplest way to pass the initial state as a second argument: @@ -283,13 +298,15 @@ const memoizedCallback = useCallback( Returns a [memoized](https://en.wikipedia.org/wiki/Memoization) callback. -Pass an inline callback and an array of inputs. `useCallback` will return a memoized version of the callback that only changes if one of the inputs has changed. This is useful when passing callbacks to optimized child components that rely on reference equality to prevent unnecessary renders (e.g. `shouldComponentUpdate`). +Pass an inline callback and an array of dependencies. `useCallback` will return a memoized version of the callback that only changes if one of the dependencies has changed. This is useful when passing callbacks to optimized child components that rely on reference equality to prevent unnecessary renders (e.g. `shouldComponentUpdate`). -`useCallback(fn, inputs)` is equivalent to `useMemo(() => fn, inputs)`. +`useCallback(fn, deps)` is equivalent to `useMemo(() => fn, deps)`. > Note > -> The array of inputs is not passed as arguments to the callback. Conceptually, though, that's what they represent: every value referenced inside the callback should also appear in the inputs array. In the future, a sufficiently advanced compiler could create this array automatically. +> The array of dependencies is not passed as arguments to the callback. Conceptually, though, that's what they represent: every value referenced inside the callback should also appear in the dependencies array. In the future, a sufficiently advanced compiler could create this array automatically. +> +> We recommend using the [`exhaustive-deps`](https://github.com/facebook/react/issues/14920) rule as part of our [`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. ### `useMemo` {#usememo} @@ -299,7 +316,7 @@ const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]); Returns a [memoized](https://en.wikipedia.org/wiki/Memoization) value. -Pass a "create" function and an array of inputs. `useMemo` will only recompute the memoized value when one of the inputs has changed. This optimization helps to avoid expensive calculations on every render. +Pass a "create" function and an array of dependencies. `useMemo` will only recompute the memoized value when one of the dependencies has changed. This optimization helps to avoid expensive calculations on every render. Remember that the function passed to `useMemo` runs during rendering. Don't do anything there that you wouldn't normally do while rendering. For example, side effects belong in `useEffect`, not `useMemo`. @@ -309,7 +326,9 @@ If no array is provided, a new value will be computed whenever a new function in > Note > -> The array of inputs is not passed as arguments to the function. Conceptually, though, that's what they represent: every value referenced inside the function should also appear in the inputs array. In the future, a sufficiently advanced compiler could create this array automatically. +> The array of dependencies is not passed as arguments to the function. Conceptually, though, that's what they represent: every value referenced inside the function should also appear in the dependencies array. In the future, a sufficiently advanced compiler could create this array automatically. +> +> We recommend using the [`exhaustive-deps`](https://github.com/facebook/react/issues/14920) rule as part of our [`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. ### `useRef` {#useref} @@ -342,7 +361,7 @@ Note that `useRef()` is useful for more than the `ref` attribute. It's [handy fo ### `useImperativeHandle` {#useimperativehandle} ```js -useImperativeHandle(ref, createHandle, [inputs]) +useImperativeHandle(ref, createHandle, [deps]) ``` `useImperativeHandle` customizes the instance value that is exposed to parent components when using `ref`. As always, imperative code using refs should be avoided in most cases. `useImperativeHandle` should be used with `forwardRef`: diff --git a/content/docs/hooks-rules.md b/content/docs/hooks-rules.md index 698d1c741..8c332578c 100644 --- a/content/docs/hooks-rules.md +++ b/content/docs/hooks-rules.md @@ -40,7 +40,8 @@ npm install eslint-plugin-react-hooks ], "rules": { // ... - "react-hooks/rules-of-hooks": "error" + "react-hooks/rules-of-hooks": "error", // Checks rules of Hooks + "react-hooks/exhaustive-deps": "warning" // Checks effect dependencies } } ``` From 3a5535d680c9fe6b646d45e9e0ef2ff8899692f8 Mon Sep 17 00:00:00 2001 From: Igor Soloydenko Date: Thu, 14 Mar 2019 16:35:04 -0700 Subject: [PATCH 04/16] resolve conflict in content/docs/hooks-effect.md --- content/docs/hooks-effect.md | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/content/docs/hooks-effect.md b/content/docs/hooks-effect.md index 2612b4e1c..3efe3c9f9 100644 --- a/content/docs/hooks-effect.md +++ b/content/docs/hooks-effect.md @@ -471,19 +471,14 @@ useEffect(() => { >Примечание > -<<<<<<< HEAD ->Если вы хотите использовать эту оптимизацию, обратите внимание на то, чтобы массив включал в себя **все значения из внешней области видимости, которые могут изменяться с течением времени, и которые будут использоваться эффектом**. В противном случае, ваш код будет ссылаться на устаревшее значение из предыдущих рендеров. Мы рассмотрим другие возможные оптимизации на странице [справочник API хуков](/docs/hooks-reference.html). +>Если вы хотите использовать эту оптимизацию, обратите внимание на то, чтобы массив включал в себя **все значения из области видимости компонента (такие как пропсы и состояние), которые могут изменяться с течением времени, и которые будут использоваться эффектом**. В противном случае, ваш код будет ссылаться на устаревшее значение из предыдущих рендеров. Отдельные страницы документации рассказывают о том, [как поступить с функциями](/docs/hooks-faq.html#is-it-safe-to-omit-functions-from-the-list-of-dependencies) и [что делать с часто изменяющимися массивами](/docs/hooks-faq.html#what-can-i-do-if-my-effect-dependencies-change-too-often). > ->Если вы хотите выполнять эффект и сбрасывать его однократно (при монтировании и размонтировании), вы можете передать пустой массив вторым аргументом. React посчитает, что ваш эффект не зависит от *каких-либо* значений из пропсов или состояния, и таким образом, он будет знать, что ему не надо его выполнять повторно. Это не расценивается как особый случай -- он напрямую следует из логики работы массивов при вводе. Хотя передача `[]` ближе по мысли к модели знакомых `componentDidMount` и `componentWillUnmount`, мы не советуем привыкать к этому, так как это часто приводит к багам, [как было рассмотрено ранее](#explanation-why-effects-run-on-each-update). Не забывайте, что React откладывает выполнение `useEffect` пока браузер не отрисует все изменения, поэтому выполнение дополнительной работы не является существенной проблемой. -======= ->If you use this optimization, make sure the array includes **all values from the component scope (such as props and state) that change over time and that are used by the effect**. Otherwise, your code will reference stale values from previous renders. Learn more about [how to deal with functions](/docs/hooks-faq.html#is-it-safe-to-omit-functions-from-the-list-of-dependencies) and [what to do when the array changes too often](/docs/hooks-faq.html#what-can-i-do-if-my-effect-dependencies-change-too-often). +>Если вы хотите выполнять эффект и сбрасывать его однократно (при монтировании и размонтировании), вы можете передать пустой массив (`[]`) вторым аргументом. React посчитает, что ваш эффект не зависит от *каких-либо* значений из пропсов или состояния и поэтому не будет выполнять повторных рендеров. Это не расценивается как особый случай -- он напрямую следует из логики работы входных массивов. > ->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. +>Если вы передадите пустой массив (`[]`), пропсы и состояние внутри эффекта всегда будут иметь значения, присвоенные им изначально. Хотя передача `[]` ближе по модели мышления к знакомым `componentDidMount` и `componentWillUnmount`, обычно есть [более хорошие](/docs/hooks-faq.html#is-it-safe-to-omit-functions-from-the-list-of-dependencies) [способы](/docs/hooks-faq.html#what-can-i-do-if-my-effect-dependencies-change-too-often) избежать частых повторных рендеров. Не забывайте, что React откладывает выполнение `useEffect`, пока браузер не отрисует все изменения, поэтому выполнение дополнительной работы не является существенной проблемой. > ->If you pass an empty array (`[]`), the props and state inside the effect will always have their initial values. While passing `[]` as the second argument is closer to the familiar `componentDidMount` and `componentWillUnmount` mental model, there are usually [better](/docs/hooks-faq.html#is-it-safe-to-omit-functions-from-the-list-of-dependencies) [solutions](/docs/hooks-faq.html#what-can-i-do-if-my-effect-dependencies-change-too-often) to avoid re-running effects too often. Also, don't forget that React defers running `useEffect` until after the browser has painted, so doing extra work is less of a problem. -> ->We recommend using the [`exhaustive-deps`](https://github.com/facebook/react/issues/14920) rule as part of our [`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. ->>>>>>> 2cd4d0cf5ddadf90446b3a5038a9bc4875151355 +>Мы рекомендуем использовать правило [`exhaustive-deps`](https://github.com/facebook/react/issues/14920), входящее в наш пакет правил линтера [`eslint-plugin-react-hooks`](https://www.npmjs.com/package/eslint-plugin-react-hooks#installation). + ## Следующие шаги {#next-steps} From ec505c73857e9cf2ed03661b720f03d060b1145e Mon Sep 17 00:00:00 2001 From: Igor Soloydenko Date: Thu, 14 Mar 2019 22:03:36 -0700 Subject: [PATCH 05/16] resolve conflicts in content/docs/hooks-faq.md --- content/docs/hooks-faq.md | 262 +++++++++++++++----------------------- 1 file changed, 103 insertions(+), 159 deletions(-) diff --git a/content/docs/hooks-faq.md b/content/docs/hooks-faq.md index f84e356bc..76380d5bc 100644 --- a/content/docs/hooks-faq.md +++ b/content/docs/hooks-faq.md @@ -18,91 +18,49 @@ prev: hooks-reference.html ).join('\n') --> -<<<<<<< HEAD -* [Внедрение хуков {#adoption-strategy}](#Внедрение-хуков-adoption-strategy) - * [В какой версии React появились хуки? {#which-versions-of-react-include-hooks}](#В-какой-версии-react-появились-хуки-which-versions-of-react-include-hooks) - * [Надо ли переписать все мои классовые компоненты? {#do-i-need-to-rewrite-all-my-class-components}](#Надо-ли-переписать-все-мои-классовые-компоненты-do-i-need-to-rewrite-all-my-class-components) - * [Что можно сделать с помощью хуков, чего невозможно добиться, используя классы? {#what-can-i-do-with-hooks-that-i-couldnt-with-classes}](#Что-можно-сделать-с-помощью-хуков-чего-невозможно-добиться-используя-классы-what-can-i-do-with-hooks-that-i-couldnt-with-classes) - * [Какая часть моих знаний о React всё ещё актуальна? {#how-much-of-my-react-knowledge-stays-relevant}](#Какая-часть-моих-знаний-о-react-всё-ещё-актуальна-how-much-of-my-react-knowledge-stays-relevant) - * [Что мне использовать: хуки, классы или оба подхода? {#should-i-use-hooks-classes-or-a-mix-of-both}](#Что-мне-использовать-хуки-классы-или-оба-подхода-should-i-use-hooks-classes-or-a-mix-of-both) - * [Дают ли хуки все возможности классов? {#do-hooks-cover-all-use-cases-for-classes}](#Дают-ли-хуки-все-возможности-классов-do-hooks-cover-all-use-cases-for-classes) - * [Являются ли хуки заменой рендер-пропсам и компонентам высшего порядка? {#do-hooks-replace-render-props-and-higher-order-components}](#Являются-ли-хуки-заменой-рендер-пропсам-и-компонентам-высшего-порядка-do-hooks-replace-render-props-and-higher-order-components) - * [Как хуки повлияют на популярные API, такие как Redux `connect()` и React Router? {#what-do-hooks-mean-for-popular-apis-like-redux-connect-and-react-router}](#Как-хуки-повлияют-на-популярные-api-такие-как-redux-connect-и-react-router-what-do-hooks-mean-for-popular-apis-like-redux-connect-and-react-router) - * [Поддерживают ли хуки статическую типизацию? {#do-hooks-work-with-static-typing}](#Поддерживают-ли-хуки-статическую-типизацию-do-hooks-work-with-static-typing) - * [Как тестировать компоненты, которые используют хуки? {#how-to-test-components-that-use-hooks}](#Как-тестировать-компоненты-которые-используют-хуки-how-to-test-components-that-use-hooks) - * [Что конкретно проверяют правила линтера в хуках?{#what-exactly-do-the-lint-rules-enforce}](#Что-конкретно-проверяют-правила-линтера-в-хукахwhat-exactly-do-the-lint-rules-enforce) -* [От классов к хукам {#from-classes-to-hooks}](#От-классов-к-хукам-from-classes-to-hooks) - * [Как методы жизненного цикла соответствуют хукам? {#how-do-lifecycle-methods-correspond-to-hooks}](#Как-методы-жизненного-цикла-соответствуют-хукам-how-do-lifecycle-methods-correspond-to-hooks) - * [Существует что-нибудь наподобие полей экземпляра? {#is-there-something-like-instance-variables}](#Существует-что-нибудь-наподобие-полей-экземпляра-is-there-something-like-instance-variables) - * [Сколько переменных состояния я могу использовать – одну или несколько? {#should-i-use-one-or-many-state-variables}](#Сколько-переменных-состояния-я-могу-использовать--одну-или-несколько-should-i-use-one-or-many-state-variables) - * [Могу ли я использовать эффект только на обновлениях компонента? {#can-i-run-an-effect-only-on-updates}](#Могу-ли-я-использовать-эффект-только-на-обновлениях-компонента-can-i-run-an-effect-only-on-updates) - * [Как получить предыдущие пропсы или состояние? {#how-to-get-the-previous-props-or-state}](#Как-получить-предыдущие-пропсы-или-состояние-how-to-get-the-previous-props-or-state) - * [Как я могу реализовать `getDerivedStateFromProps`? {#how-do-i-implement-getderivedstatefromprops}](#Как-я-могу-реализовать-getderivedstatefromprops-how-do-i-implement-getderivedstatefromprops) - * [Существует что-нибудь наподобие forceUpdate? {#is-there-something-like-forceupdate}](#Существует-что-нибудь-наподобие-forceupdate-is-there-something-like-forceupdate) - * [Могу ли я изменить реф, переданный в функциональный компонент? {#can-i-make-a-ref-to-a-function-component}](#Могу-ли-я-изменить-реф-переданный-в-функциональный-компонент-can-i-make-a-ref-to-a-function-component) - * [Что значит `const [thing, setThing] = useState()`? {#what-does-const-thing-setthing--usestate-mean}](#Что-значит-const-thing-setthing--usestate-what-does-const-thing-setthing--usestate-mean) -* [Оптимизации производительности {#performance-optimizations}](#Оптимизации-производительности-performance-optimizations) - * [Могу ли я пропустить эффект при обновлениях? {#can-i-skip-an-effect-on-updates}](#Могу-ли-я-пропустить-эффект-при-обновлениях-can-i-skip-an-effect-on-updates) - * [Как я могу реализовать `shouldComponentUpdate`? {#how-do-i-implement-shouldcomponentupdate}](#Как-я-могу-реализовать-shouldcomponentupdate-how-do-i-implement-shouldcomponentupdate) - * [Как закешировать вычисления? {#how-to-memoize-calculations}](#Как-закешировать-вычисления-how-to-memoize-calculations) - * [Как лениво создавать большие объекты? {#how-to-create-expensive-objects-lazily}](#Как-лениво-создавать-большие-объекты-how-to-create-expensive-objects-lazily) - * [Являются ли хуки медленными из-за создания функций на каждом рендере? {#are-hooks-slow-because-of-creating-functions-in-render}](#Являются-ли-хуки-медленными-из-за-создания-функций-на-каждом-рендере-are-hooks-slow-because-of-creating-functions-in-render) - * [Как избежать передачи колбэков вниз? {#how-to-avoid-passing-callbacks-down}](#Как-избежать-передачи-колбэков-вниз-how-to-avoid-passing-callbacks-down) - * [Как получить часто изменяемое значение из хука `useCallback`? {#how-to-read-an-often-changing-value-from-usecallback}](#Как-получить-часто-изменяемое-значение-из-хука-usecallback-how-to-read-an-often-changing-value-from-usecallback) -* [Под капотом {#under-the-hood}](#Под-капотом-under-the-hood) - * [Как React связывает вызовы хуков с компонентом? {#how-does-react-associate-hook-calls-with-components}](#Как-react-связывает-вызовы-хуков-с-компонентом-how-does-react-associate-hook-calls-with-components) - * [Что послужило прообразом хуков? {#what-is-the-prior-art-for-hooks}](#Что-послужило-прообразом-хуков-what-is-the-prior-art-for-hooks) +* [Внедрение хуков](#adoption-strategy) + * [В какой версии React появились хуки?](#which-versions-of-react-include-hooks) + * [Надо ли переписать все мои классовые компоненты?](#do-i-need-to-rewrite-all-my-class-components) + * [Что можно сделать с помощью хуков, чего невозможно добиться, используя классы?](#what-can-i-do-with-hooks-that-i-couldnt-with-classes) + * [Какая часть моих знаний о React всё ещё актуальна?](#how-much-of-my-react-knowledge-stays-relevant) + * [Что мне использовать: хуки, классы или оба подхода?](#should-i-use-hooks-classes-or-a-mix-of-both) + * [Дают ли хуки все возможности классов?](#do-hooks-cover-all-use-cases-for-classes) + * [Являются ли хуки заменой рендер-пропсам и компонентам высшего порядка?](#do-hooks-replace-render-props-and-higher-order-components) + * [Как хуки повлияют на популярные API, такие как Redux `connect()` и React Router?](#what-do-hooks-mean-for-popular-apis-like-redux-connect-and-react-router) + * [Поддерживают ли хуки статическую типизацию?](#do-hooks-work-with-static-typing) + * [Как тестировать компоненты, которые используют хуки?](#how-to-test-components-that-use-hooks) + * [Что конкретно проверяют правила линтера в хуках?](#what-exactly-do-the-lint-rules-enforce) +* [От классов к хукам](#from-classes-to-hooks) + * [Как методы жизненного цикла соответствуют хукам?](#how-do-lifecycle-methods-correspond-to-hooks) + * [Как осуществлять запросы данных с помощью хуков?](#how-can-i-do-data-fetching) + * [Существует что-нибудь наподобие полей экземпляра?](#is-there-something-like-instance-variables) + * [Сколько переменных состояния я могу использовать – одну или несколько?](#should-i-use-one-or-many-state-variables) + * [Могу ли я использовать эффект только на обновлениях компонента?](#can-i-run-an-effect-only-on-updates) + * [Как получить предыдущие пропсы или состояние?](#how-to-get-the-previous-props-or-state) + * [Почему я вижу устаревшие пропсы или состояние в моей функции?](#why-am-i-seeing-stale-props-or-state-inside-my-function) + * [Как я могу реализовать `getDerivedStateFromProps`?](#how-do-i-implement-getderivedstatefromprops) + * [Существует что-нибудь наподобие forceUpdate?](#is-there-something-like-forceupdate) + * [Могу ли я изменить реф, переданный в функциональный компонент?](#can-i-make-a-ref-to-a-function-component) + * [Что значит `const [thing, setThing] = useState()`?](#what-does-const-thing-setthing--usestate-mean) +* [Оптимизации производительности](#performance-optimizations) + * [Могу ли я пропустить эффект при обновлениях?](#can-i-skip-an-effect-on-updates) + * [Безопасно ли не указывать функции в списке зависимостей?](#is-it-safe-to-omit-functions-from-the-list-of-dependencies) + * [Что делать, если зависимости эффекта изменяются слишком часто?](#what-can-i-do-if-my-effect-dependencies-change-too-often) + * [Как я могу реализовать `shouldComponentUpdate`?](#how-do-i-implement-shouldcomponentupdate) + * [Как закешировать вычисления?](#how-to-memoize-calculations) + * [Как лениво создавать большие объекты?](#how-to-create-expensive-objects-lazily) + * [Являются ли хуки медленными из-за создания функций на каждом рендере?](#are-hooks-slow-because-of-creating-functions-in-render) + * [Как избежать передачи колбэков вниз?](#how-to-avoid-passing-callbacks-down) + * [Как получить часто изменяемое значение из хука `useCallback`?](#how-to-read-an-often-changing-value-from-usecallback) +* [Под капотом](#under-the-hood) + * [Как React связывает вызовы хуков с компонентом?](#how-does-react-associate-hook-calls-with-components) + * [Что послужило прообразом хуков?](#what-is-the-prior-art-for-hooks) ## Внедрение хуков {#adoption-strategy} ### В какой версии React появились хуки? {#which-versions-of-react-include-hooks} Начиная с релиза 16.8.0, React включает в себя стабильную реализацию хуков для: -======= -* **[Adoption Strategy](#adoption-strategy)** - * [Which versions of React include Hooks?](#which-versions-of-react-include-hooks) - * [Do I need to rewrite all my class components?](#do-i-need-to-rewrite-all-my-class-components) - * [What can I do with Hooks that I couldn't with classes?](#what-can-i-do-with-hooks-that-i-couldnt-with-classes) - * [How much of my React knowledge stays relevant?](#how-much-of-my-react-knowledge-stays-relevant) - * [Should I use Hooks, classes, or a mix of both?](#should-i-use-hooks-classes-or-a-mix-of-both) - * [Do Hooks cover all use cases for classes?](#do-hooks-cover-all-use-cases-for-classes) - * [Do Hooks replace render props and higher-order components?](#do-hooks-replace-render-props-and-higher-order-components) - * [What do Hooks mean for popular APIs like Redux connect() and React Router?](#what-do-hooks-mean-for-popular-apis-like-redux-connect-and-react-router) - * [Do Hooks work with static typing?](#do-hooks-work-with-static-typing) - * [How to test components that use Hooks?](#how-to-test-components-that-use-hooks) - * [What exactly do the lint rules enforce?](#what-exactly-do-the-lint-rules-enforce) -* **[From Classes to Hooks](#from-classes-to-hooks)** - * [How do lifecycle methods correspond to Hooks?](#how-do-lifecycle-methods-correspond-to-hooks) - * [How can I do data fetching with Hooks?](#how-can-i-do-data-fetching-with-hooks) - * [Is there something like instance variables?](#is-there-something-like-instance-variables) - * [Should I use one or many state variables?](#should-i-use-one-or-many-state-variables) - * [Can I run an effect only on updates?](#can-i-run-an-effect-only-on-updates) - * [How to get the previous props or state?](#how-to-get-the-previous-props-or-state) - * [Why am I seeing stale props or state inside my function?](#why-am-i-seeing-stale-props-or-state-inside-my-function) - * [How do I implement getDerivedStateFromProps?](#how-do-i-implement-getderivedstatefromprops) - * [Is there something like forceUpdate?](#is-there-something-like-forceupdate) - * [Can I make a ref to a function component?](#can-i-make-a-ref-to-a-function-component) - * [What does const [thing, setThing] = useState() mean?](#what-does-const-thing-setthing--usestate-mean) -* **[Performance Optimizations](#performance-optimizations)** - * [Can I skip an effect on updates?](#can-i-skip-an-effect-on-updates) - * [Is it safe to omit functions from the list of dependencies?](#is-it-safe-to-omit-functions-from-the-list-of-dependencies) - * [What can I do if my effect dependencies change too often?](#what-can-i-do-if-my-effect-dependencies-change-too-often) - * [How do I implement shouldComponentUpdate?](#how-do-i-implement-shouldcomponentupdate) - * [How to memoize calculations?](#how-to-memoize-calculations) - * [How to create expensive objects lazily?](#how-to-create-expensive-objects-lazily) - * [Are Hooks slow because of creating functions in render?](#are-hooks-slow-because-of-creating-functions-in-render) - * [How to avoid passing callbacks down?](#how-to-avoid-passing-callbacks-down) - * [How to read an often-changing value from useCallback?](#how-to-read-an-often-changing-value-from-usecallback) -* **[Under the Hood](#under-the-hood)** - * [How does React associate Hook calls with components?](#how-does-react-associate-hook-calls-with-components) - * [What is the prior art for Hooks?](#what-is-the-prior-art-for-hooks) - -## Adoption Strategy {#adoption-strategy} - -### Which versions of React include Hooks? {#which-versions-of-react-include-hooks} - -Starting with 16.8.0, React includes a stable implementation of React Hooks for: ->>>>>>> 2cd4d0cf5ddadf90446b3a5038a9bc4875151355 * React DOM * React DOM Server @@ -249,15 +207,13 @@ it('can render and update a counter', () => { * `componentDidMount`, `componentDidUpdate`, `componentWillUnmount`: [Хук `useEffect`](/docs/hooks-reference.html#useeffect) заменяет все их комбинации (включая [более](#can-i-skip-an-effect-on-updates) [редкие](#can-i-run-an-effect-only-on-updates) случаи). -<<<<<<< HEAD * `componentDidCatch` и `getDerivedStateFromError`: В данный момент не существует хуков-аналогов для этих методов, но они будут скоро добавлены. -======= -### How can I do data fetching with Hooks? -Check out [this article](https://www.robinwieruch.de/react-hooks-fetch-data/) to learn more about data fetching with Hooks. +### Как осуществлять запросы данных с помощью хуков? {#how-can-i-do-data-fetching} + +Ознакомьтесь [со статьёй](https://www.robinwieruch.de/react-hooks-fetch-data/), которая рассказывает, как делать запросы данных с помощью хуков. ### Is there something like instance variables? {#is-there-something-like-instance-variables} ->>>>>>> 2cd4d0cf5ddadf90446b3a5038a9bc4875151355 ### Существует что-нибудь наподобие полей экземпляра? {#is-there-something-like-instance-variables} @@ -418,12 +374,9 @@ function Counter() { Также смотрите [рекомендованный паттерн для производного состояния](#how-do-i-implement-getderivedstatefromprops). -<<<<<<< HEAD -### Как я могу реализовать `getDerivedStateFromProps`? {#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} +### Почему я вижу устаревшие пропсы или состояние в моей функции? {#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 created in. For example, consider code like this: +Любая функция внутри компонента, включая эффекты и обработчики событий, "видит" пропсы и состояние из функции `render()`, в которой она была создана. Рассмотрим такой код: ```js function Example() { @@ -431,36 +384,36 @@ function Example() { function handleAlertClick() { setTimeout(() => { - alert('You clicked on: ' + count); + alert('Вы кликнули по: ' + count); }, 3000); } return (
-

You clicked {count} times

+

Вы кликнули {count} раз(а)

); } ``` -If you first click "Show alert" and then increment the counter, the alert will show the `count` variable **at the time you clicked the "Show alert" button**. This prevents bugs caused by the code assuming props and state don't change. +Если вы сперва кликните по "Показать предупреждение", а потом увеличите счётчик, то предупреждение отобразит значение переменной `count` **на момент нажатия по кнопке "Показать предупреждение"**. Такое поведение предотвращает баги в коде, который предполагает, что пропсы и состояние не меняются. -If you intentionally want to read the *latest* state from some asynchronous callback, you could keep it in [a ref](/docs/hooks-faq.html#is-there-something-like-instance-variables), mutate it, and read from it. +Если вы намеренно хотите считать из асинхронного колбэка *свежайшее* состояние, вы можете сперва сохранить его [в реф](/docs/hooks-faq.html#is-there-something-like-instance-variables), потом изменить его и затем считать его из рефа. -Finally, another possible reason you're seeing stale props or state is if you use the "dependency array" optimization but didn't correctly specify all the dependencies. For example, if an effect specifies `[]` as the second argument but reads `someProp` inside, it will keep "seeing" the initial value of `someProp`. The solution is to either remove the dependency array, or to fix it. Here's [how you can deal with functions](#is-it-safe-to-omit-functions-from-the-list-of-dependencies), and here's [other common strategies](#what-can-i-do-if-my-effect-dependencies-change-too-often) to run effects less often without incorrectly skipping dependencies. +Наконец, возможна другая ситуация, почему вы видите устаревшие пропсы или состояние: когда вы используете оптимизацию с помощью "массива зависимостей", но неправильно указали какие-то зависимости. Например, если эффект передаёт вторым параметром `[]`, но при этом использует `someProp`, то он продолжит "видеть" исходное значение `someProp`. Правильным решением является либо исправление массива, либо отказ от его использования. +По этим ссылкам описаны [подходы к функциям](#is-it-safe-to-omit-functions-from-the-list-of-dependencies) в аналогичных ситуациях и [другие известные способы](#what-can-i-do-if-my-effect-dependencies-change-too-often) снижения частоты вызова эффектов, исключающие передачу неправильных зависимостей. ->Note +>Примечание > ->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. +>Мы предоставляем правило [`exhaustive-deps`](https://github.com/facebook/react/issues/14920) в нашем пакете линтера [`eslint-plugin-react-hooks`](https://www.npmjs.com/package/eslint-plugin-react-hooks#installation). Оно предупреждает о неправильно указанных зависимостях и рекомендует их исправить. -### How do I implement `getDerivedStateFromProps`? {#how-do-i-implement-getderivedstatefromprops} ->>>>>>> 2cd4d0cf5ddadf90446b3a5038a9bc4875151355 +### Как я могу реализовать `getDerivedStateFromProps`? {#how-do-i-implement-getderivedstatefromprops} Несмотря на то, что вам скорее всего [это не нужно](/blog/2018/06/07/you-probably-dont-need-derived-state.html), в редких случаях (например, для реализации компонента ``), вы можете изменять состояние прямо во время рендера. React моментально сделает повторный рендер компонента с обновлённым состоянием сразу после первого рендера, и это не будет затратно. @@ -515,12 +468,9 @@ function ScrollView({row}) { Да. Ознакомьтесь с [условным вызовом эффектов](/docs/hooks-reference.html#conditionally-firing-an-effect). Обратите внимание, что забыв обработать обновления, вы зачастую можете [создать ошибки](/docs/hooks-effect.html#explanation-why-effects-run-on-each-update). Поэтому это и не является поведением по умолчанию. -<<<<<<< HEAD -### Как я могу реализовать `shouldComponentUpdate`? {#how-do-i-implement-shouldcomponentupdate} -======= -### Is it safe to omit functions from the list of dependencies? {#is-it-safe-to-omit-functions-from-the-list-of-dependencies} +### Безопасно ли не указывать функции в списке зависимостей? {#is-it-safe-to-omit-functions-from-the-list-of-dependencies} -Generally speaking, no. +Вообще говоря, это небезопасно. ```js{3,8} function Example() { @@ -530,11 +480,11 @@ function Example() { useEffect(() => { doSomething(); - }, []); // 🔴 This is not safe (it calls `doSomething` which uses `someProp`) + }, []); // 🔴 Так делать небезопасно (вызывать `doSomething`, который использует `someProp`) } ``` -It's difficult to remember which props or state are used by functions outside of the effect. This is why **usually you'll want to declare functions needed by an effect *inside* of it.** Then it's easy to see what values from the component scope that effect depends on: +Сложно помнить, какие пропсы и состояние используются функцией определённой вне эффекта. Именно поэтому, **лучше объявлять функции нужные эффекту *внутри* него**. Тогда легче увидеть, от каких значений из области видимости компонента зависит эффект: ```js{4,8} function Example() { @@ -544,59 +494,60 @@ function Example() { } doSomething(); - }, [someProp]); // ✅ OK (our effect only uses `someProp`) + }, [someProp]); // ✅ Правильно (наш эффект использует только `someProp`) } ``` -If after that we still don't use any values from the component scope, it's safe to specify `[]`: +Если после такого изменения мы видим, что никакие значения из области видимости компонента не используются, то можно безопасно указать `[]`: -```js{7} +```js{7-8} useEffect(() => { function doSomething() { - console.log('hello'); + console.log('Привет'); } doSomething(); -}, []); // ✅ OK in this example because we don't use *any* values from component scope +}, []); // ✅ Так можно поступить в этом примере, потому что + // нет зависимости от значений из области видимости компонента ``` -Depending on your use case, there are a few more options described below. +В зависимости от ситуации, может пригодиться один из вариантов, описанных ниже. ->Note +>Примечание > ->We provide the [`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 help you find components that don't handle updates consistently. +>Мы предоставляем правило [`exhaustive-deps`](https://github.com/facebook/react/issues/14920) в пакете нашего линтера [`eslint-plugin-react-hooks`](https://www.npmjs.com/package/eslint-plugin-react-hooks#installation). Оно поможет выяалять компоненты, не обрабатывающие обновления должным образом. -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, and anything derived from them. +Когда вы указываете [список зависимостей](/docs/hooks-reference.html#conditionally-firing-an-effect) через последний аргумент хуков `useEffect`, `useMemo`, `useCallback` или `useImperativeHandle`, в него должны войти все использованные значения, которые задействованы в потоке данных React, включая пропсы, состояние и их производные. -It is **only** safe to omit a function from the dependency list if nothing in it (or the functions called by it) references props, state, or values derived from them. This example has a bug: +Безопасно опускать в списке **только** те функции, которые не используют ни сами, ни через функции, которые они вызывают, пропсы, состояние или их производные. Так, в следующем примере показан баг: ```js{5,12} function ProductPage({ productId }) { const [product, setProduct] = useState(null); async function fetchProduct() { - const response = await fetch('http://myapi/product' + productId); // Uses productId prop + const response = await fetch('http://myapi/product' + productId); // Использует проп productId const json = await response.json(); setProduct(json); } useEffect(() => { fetchProduct(); - }, []); // 🔴 Invalid because `fetchProduct` uses `productId` + }, []); // 🔴 Неправильно, потому что `fetchProduct` использует `productId` // ... } ``` -**The recommended fix is to move that function _inside_ of your effect**. That makes it easy to see which props or state your effect uses, and to ensure they're all declared: +**Рекомендованное исправлять такой код, перемещая функцию _внутрь_ вашего эффекта**. Это помогает замечать, какие пропсы и состояние используются вашим эффектом, и убедиться, что они перечислены в списке зависимостей: ```js{5-10,13} function ProductPage({ productId }) { const [product, setProduct] = useState(null); useEffect(() => { - // By moving this function inside the effect, we can clearly see the values it uses. + // Переместив эту функцию внутрь эффекта, мы ясно видим, какие значения она использует. async function fetchProduct() { const response = await fetch('http://myapi/product' + productId); const json = await response.json(); @@ -604,12 +555,12 @@ function ProductPage({ productId }) { } fetchProduct(); - }, [productId]); // ✅ Valid because our effect only uses productId + }, [productId]); // ✅ Правильно, потому что эффект использует только productId // ... } ``` -This also allows you to handle out-of-order responses with a local variable inside the effect: +Это также позволяет обрабатывать ответы, пришедшие не в порядке запросов, с помощью локальной переменной внутри эффекта: ```js{2,6,8} useEffect(() => { @@ -623,24 +574,24 @@ This also allows you to handle out-of-order responses with a local variable insi }, [productId]); ``` -We moved the function inside the effect so it doesn't need to be in its dependency list. +Мы переместили функцию внутрь эффекта, так что её не нужно указывать в списке зависимостей. ->Tip +>Совет > ->Check out [this article](https://www.robinwieruch.de/react-hooks-fetch-data/) to learn more about data fetching with Hooks. +>Прочитайте [эту статью](https://www.robinwieruch.de/react-hooks-fetch-data/), чтобы узнать больше о том, как запрашивать данные с помощью хуков. -**If for some reason you _can't_ move a function inside an effect, there are a few more options:** +**Если по какой-то причине вы _не_ можете переместить функцию в эффект, есть другие варианты:** -* **You can try moving that function outside of your component**. In that case, the function is guaranteed to not reference any props or state, and also doesn't need to be in the list of dependencies. -* If the function you're calling is a pure computation and is safe to call while rendering, you may **call it outside of the effect instead,** and make the effect depend on the returned value. -* As a last resort, you can **add a function to effect dependencies but _wrap its definition_** into the [`useCallback`](/docs/hooks-reference.html#usecallback) Hook. This ensures it doesn't change on every render unless *its own* dependencies also change: +* **Можно попробовать поместить функцию снаружи компонента**. В таком случае она гарантированно не будет ссылаться на пропсы и состояние, так что её не требуется перечислять в списке зависимостей. +* Если функция, которую вы вызываете, является чистым вычислением и её безопасно вызывать во время рендера, вы можете **вызвать её снаружи эффекта, а не внутри**, и сделать эффект зависящим от результата этого вызова, а не от самой функции. +* В крайнем случае можете **добавить саму функцию в список зависимостей эффекта, но _обернув её определение_** в хук [`useCallback`](/docs/hooks-reference.html#usecallback). Тогда функция будет оставаться неизменной, до тех пор, пока не изменятся её зависимости: -```js{2-5} +```js{2-5,13} function ProductPage({ productId }) { - // ✅ Wrap with useCallback to avoid change on every render + // ✅ Оборачиваем в useCallback, чтобы избежать изменений при каждом рендере const fetchProduct = useCallback(() => { - // ... Does something with productId ... - }, [productId]); // ✅ All useCallback dependencies are specified + // ... Что-то делаем с productId ... + }, [productId]); // ✅ Перечисляем все зависимости useCallback return ; } @@ -648,16 +599,16 @@ function ProductPage({ productId }) { function ProductDetails({ fetchProduct }) useEffect(() => { fetchProduct(); - }, [fetchProduct]); // ✅ All useEffect dependencies are specified + }, [fetchProduct]); // ✅ Перечисляем все зависимости useEffect // ... } ``` -Note that in the above example we **need** to keep the function in the dependencies list. This ensures that a change in the `productId` prop of `ProductPage` automatically triggers a refetch in the `ProductDetails` component. +Заметьте, что в примере выше мы всё ещё **должны** указать функцию в списке зависимостей. Тогда гарантируется, что изменение пропа `productId` у `ProductPage` приведёт к повторному запрашиванию данных в компоненте `ProductDetails`. -### What can I do if my effect dependencies change too often? +### Что делать, если зависимости эффекта изменяются слишком часто? {#what-can-i-do-if-my-effect-dependencies-change-too-often} -Sometimes, your effect may be using reading state that changes too often. You might be tempted to omit that state from a list of dependencies, but that usually leads to bugs: +Бывают случаи, когда эффект может зависеть от состояние, которое очень часто изменяется. У вас может возникнуть желание не включать это состояние в список зависимостей хука, но это как правило приводит к багам: ```js{6,9} function Counter() { @@ -665,16 +616,16 @@ function Counter() { useEffect(() => { const id = setInterval(() => { - setCount(count + 1); // This effect depends on the `count` state + setCount(count + 1); // Этот эффект зависит от переменной состояния `count` }, 1000); return () => clearInterval(id); - }, []); // 🔴 Bug: `count` is not specified as a dependency + }, []); // 🔴 Баг: `count` не указан в качестве зависимости return

{count}

; } ``` -Specifying `[count]` as a list of dependencies would fix the bug, but would cause the interval to be reset on every change. That may not be desirable. To fix this, we can use the [functional update form of `setState`](/docs/hooks-reference.html#functional-updates). It lets us specify *how* the state needs to change without referencing the *current* state: +Если переписать список зависимостей как `[count]`, то баг будет устранён, но это приведёт к сбрасыванию интервала при каждом изменении. Такое поведение может быть нежелательно. Чтобы исправить это, мы можем применить [форму функционального обновления хука `setState`](/docs/hooks-reference.html#functional-updates), которая позволяет указать, *как* должно меняться состояние, не ссылаясь явно на *текущее* состояние: ```js{6,9} function Counter() { @@ -682,24 +633,24 @@ function Counter() { useEffect(() => { const id = setInterval(() => { - setCount(c => c + 1); // ✅ This doesn't depend on `count` variable outside + setCount(c => c + 1); // ✅ Эта строчка не зависит от внешней переменной `count` }, 1000); return () => clearInterval(id); - }, []); // ✅ Our effect doesn't use any variables in the component scope + }, []); // ✅ Наш эффект не использует никаких переменных из области видимости компонента return

{count}

; } ``` -(The identity of the `setCount` function is guaranteed to be stable so it's safe to omit.) +(Идентичность функции `setCount` гарантирована, поэтому её можно безопасно не включать в список зависимостей.) -In more complex cases (such as if one state depends on another state), try moving the state update logic outside the effect with the [`useReducer` Hook](/docs/hooks-reference.html#usereducer). [This article](https://adamrackis.dev/state-and-use-reducer/) offers an example of how you can do this. **The identity of the `dispatch` function from `useReducer` is always stable** — even if the reducer function is declared inside the component and reads its props. +В более сложных случаях (например, когда одно состояние зависит от другого), попробуйте перенести логику обновления состояния из хука эффекта в хук [`useReducer`](/docs/hooks-reference.html#usereducer). [Эта статья](https://adamrackis.dev/state-and-use-reducer/) иллюстрирует пример того, как это сделать. **Идентичность функции `dispatch` из хука `useReducer` всегда стабильна** — даже если функция редюсера объявлена внутри компонента и считывает его пропсы. -As a last resort, if you want to something like `this` in a class, you can [use a ref](/docs/hooks-faq.html#is-there-something-like-instance-variables) to hold a mutable variable. Then you can write and read to it. For example: +В крайнем случае если вы хотите реализовать что-то наподобие `this` в классах, вы можете [использовать реф](/docs/hooks-faq.html#is-there-something-like-instance-variables), чтобы хранить в нём изменяемую переменную. Тогда можно писать и читать из него. Например: ```js{2-6,10-11,16} function Example(props) { - // Keep latest props in a ref. + // Сохраняем свежайшие значения пропсов в ref let latestProps = useRef(props); useEffect(() => { latestProps.current = props; @@ -707,20 +658,19 @@ function Example(props) { useEffect(() => { function tick() { - // Read latest props at any time + // Считываем свежайшие значения пропсов в любое время console.log(latestProps.current); } const id = setInterval(tick, 1000); return () => clearInterval(id); - }, []); // This effect never re-runs + }, []); // Этот эффект никогда не исполняется повторно } ``` -Only do this if you couldn't find a better alternative, as relying on mutation makes components less predictable. If there's a specific pattern that doesn't translate well, [file an issue](https://github.com/facebook/react/issues/new) with a runnable example code and we can try to help. +Рекомендуется прибегать к этому подходу только если не удалось найти лучшей альтернативы, поскольку компоненты, полагающиеся на изменчивость, менее предсказуемы. Если какой-то конкретный паттерн плохо получается выразить, [откройте ишью на GitHub](https://github.com/facebook/react/issues/new) с примером исполняемого кода и мы постараемся помочь. -### How do I implement `shouldComponentUpdate`? {#how-do-i-implement-shouldcomponentupdate} ->>>>>>> 2cd4d0cf5ddadf90446b3a5038a9bc4875151355 +### Как я могу реализовать `shouldComponentUpdate`? {#how-do-i-implement-shouldcomponentupdate} Вы можете обернуть функциональный компонент в вызов `React.memo` для поверхностного сравнения его пропсов: @@ -734,15 +684,9 @@ const Button = React.memo((props) => { `React.memo` не сравнивает состояние, потому что не существует единого объекта, который можно сравнить. Но вы можете также сделать дочерние компоненты чистыми или даже [оптимизировать определённые дочерние компоненты, используя хук `useMemo`](/docs/hooks-faq.html#how-to-memoize-calculations). -<<<<<<< HEAD ### Как закешировать вычисления? {#how-to-memoize-calculations} Хук [`useMemo`](/docs/hooks-reference.html#usememo) позволяет вам закэшировать вычисления между несколькими рендерами, путём запоминания прошлого результата: -======= -### How to memoize calculations? {#how-to-memoize-calculations} - -The [`useMemo`](/docs/hooks-reference.html#usememo) Hook lets you cache calculations between multiple renders by "remembering" the previous computation: ->>>>>>> 2cd4d0cf5ddadf90446b3a5038a9bc4875151355 ```js const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]); From dc5ee9d803145ef65148fe59914a367fe7d63dc3 Mon Sep 17 00:00:00 2001 From: Nick Tishkevich Date: Sat, 16 Mar 2019 12:05:40 -0700 Subject: [PATCH 06/16] Update content/docs/hooks-faq.md Co-Authored-By: another-guy --- content/docs/hooks-faq.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/hooks-faq.md b/content/docs/hooks-faq.md index 76380d5bc..9a0d92a00 100644 --- a/content/docs/hooks-faq.md +++ b/content/docs/hooks-faq.md @@ -211,7 +211,7 @@ it('can render and update a counter', () => { ### Как осуществлять запросы данных с помощью хуков? {#how-can-i-do-data-fetching} -Ознакомьтесь [со статьёй](https://www.robinwieruch.de/react-hooks-fetch-data/), которая рассказывает, как делать запросы данных с помощью хуков. +Ознакомьтесь [со статьёй](https://www.robinwieruch.de/react-hooks-fetch-data/), которая рассказывает как делать запросы данных с помощью хуков. ### Is there something like instance variables? {#is-there-something-like-instance-variables} From 138d8072d1ce55cab75181bfb824c1ee75a468c2 Mon Sep 17 00:00:00 2001 From: Vlad Date: Sat, 16 Mar 2019 16:06:51 -0700 Subject: [PATCH 07/16] Update content/docs/hooks-effect.md Co-Authored-By: another-guy --- content/docs/hooks-effect.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/hooks-effect.md b/content/docs/hooks-effect.md index 3efe3c9f9..03a75df56 100644 --- a/content/docs/hooks-effect.md +++ b/content/docs/hooks-effect.md @@ -477,7 +477,7 @@ useEffect(() => { > >Если вы передадите пустой массив (`[]`), пропсы и состояние внутри эффекта всегда будут иметь значения, присвоенные им изначально. Хотя передача `[]` ближе по модели мышления к знакомым `componentDidMount` и `componentWillUnmount`, обычно есть [более хорошие](/docs/hooks-faq.html#is-it-safe-to-omit-functions-from-the-list-of-dependencies) [способы](/docs/hooks-faq.html#what-can-i-do-if-my-effect-dependencies-change-too-often) избежать частых повторных рендеров. Не забывайте, что React откладывает выполнение `useEffect`, пока браузер не отрисует все изменения, поэтому выполнение дополнительной работы не является существенной проблемой. > ->Мы рекомендуем использовать правило [`exhaustive-deps`](https://github.com/facebook/react/issues/14920), входящее в наш пакет правил линтера [`eslint-plugin-react-hooks`](https://www.npmjs.com/package/eslint-plugin-react-hooks#installation). +>Мы рекомендуем использовать правило [`exhaustive-deps`](https://github.com/facebook/react/issues/14920), входящее в наш пакет правил линтера [`eslint-plugin-react-hooks`](https://www.npmjs.com/package/eslint-plugin-react-hooks#installation). Оно предупреждает, когда зависимости указаны неправильно и предлагает исправление. ## Следующие шаги {#next-steps} From af67becdd37f35b78fbf9069a8ad353f5ea5d668 Mon Sep 17 00:00:00 2001 From: ANOTHER GUY Date: Sat, 16 Mar 2019 16:09:30 -0700 Subject: [PATCH 08/16] Update hooks-faq.md --- content/docs/hooks-faq.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/content/docs/hooks-faq.md b/content/docs/hooks-faq.md index 9a0d92a00..bb64b581b 100644 --- a/content/docs/hooks-faq.md +++ b/content/docs/hooks-faq.md @@ -213,8 +213,6 @@ it('can render and update a counter', () => { Ознакомьтесь [со статьёй](https://www.robinwieruch.de/react-hooks-fetch-data/), которая рассказывает как делать запросы данных с помощью хуков. -### Is there something like instance variables? {#is-there-something-like-instance-variables} - ### Существует что-нибудь наподобие полей экземпляра? {#is-there-something-like-instance-variables} Да! Хук [`useRef()`](/docs/hooks-reference.html#useref) может использоваться не только для DOM-рефов. Реф – это общий контейнер, а его поле `current` -- изменяемое и может хранить любое значение, подобно полю экземпляра класса. From 986d0cdbec7e6f307750d5194321297f4c90bbfb Mon Sep 17 00:00:00 2001 From: Vlad Date: Sat, 16 Mar 2019 16:12:34 -0700 Subject: [PATCH 09/16] Update content/docs/hooks-faq.md Co-Authored-By: another-guy --- content/docs/hooks-faq.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/hooks-faq.md b/content/docs/hooks-faq.md index bb64b581b..acd12b2c5 100644 --- a/content/docs/hooks-faq.md +++ b/content/docs/hooks-faq.md @@ -20,7 +20,7 @@ prev: hooks-reference.html * [Внедрение хуков](#adoption-strategy) * [В какой версии React появились хуки?](#which-versions-of-react-include-hooks) - * [Надо ли переписать все мои классовые компоненты?](#do-i-need-to-rewrite-all-my-class-components) + * [Нужно ли переписать все мои классовые компоненты?](#do-i-need-to-rewrite-all-my-class-components) * [Что можно сделать с помощью хуков, чего невозможно добиться, используя классы?](#what-can-i-do-with-hooks-that-i-couldnt-with-classes) * [Какая часть моих знаний о React всё ещё актуальна?](#how-much-of-my-react-knowledge-stays-relevant) * [Что мне использовать: хуки, классы или оба подхода?](#should-i-use-hooks-classes-or-a-mix-of-both) From 8a335129ed9252febfab643f20e5f575c38eb1c3 Mon Sep 17 00:00:00 2001 From: Vlad Date: Sat, 16 Mar 2019 16:12:46 -0700 Subject: [PATCH 10/16] Update content/docs/hooks-faq.md Co-Authored-By: another-guy --- content/docs/hooks-faq.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/hooks-faq.md b/content/docs/hooks-faq.md index acd12b2c5..74225bd91 100644 --- a/content/docs/hooks-faq.md +++ b/content/docs/hooks-faq.md @@ -209,7 +209,7 @@ it('can render and update a counter', () => { * `componentDidCatch` и `getDerivedStateFromError`: В данный момент не существует хуков-аналогов для этих методов, но они будут скоро добавлены. -### Как осуществлять запросы данных с помощью хуков? {#how-can-i-do-data-fetching} +### Как осуществлять запросы данных с помощью хуков? {#how-can-i-do-data-fetching-with-hooks} Ознакомьтесь [со статьёй](https://www.robinwieruch.de/react-hooks-fetch-data/), которая рассказывает как делать запросы данных с помощью хуков. From 11fe134eee70bb45f1dab4e31c235782663dee7b Mon Sep 17 00:00:00 2001 From: Vlad Date: Sat, 16 Mar 2019 16:13:00 -0700 Subject: [PATCH 11/16] Update content/docs/hooks-faq.md Co-Authored-By: another-guy --- content/docs/hooks-faq.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/hooks-faq.md b/content/docs/hooks-faq.md index 74225bd91..cba39df24 100644 --- a/content/docs/hooks-faq.md +++ b/content/docs/hooks-faq.md @@ -32,7 +32,7 @@ prev: hooks-reference.html * [Что конкретно проверяют правила линтера в хуках?](#what-exactly-do-the-lint-rules-enforce) * [От классов к хукам](#from-classes-to-hooks) * [Как методы жизненного цикла соответствуют хукам?](#how-do-lifecycle-methods-correspond-to-hooks) - * [Как осуществлять запросы данных с помощью хуков?](#how-can-i-do-data-fetching) + * [Как осуществлять запросы данных с помощью хуков?](#how-can-i-do-data-fetching-with-hooks) * [Существует что-нибудь наподобие полей экземпляра?](#is-there-something-like-instance-variables) * [Сколько переменных состояния я могу использовать – одну или несколько?](#should-i-use-one-or-many-state-variables) * [Могу ли я использовать эффект только на обновлениях компонента?](#can-i-run-an-effect-only-on-updates) From e38adaeb52d2ab408bf5ed864ae6638edaf6e83a Mon Sep 17 00:00:00 2001 From: ANOTHER GUY Date: Sat, 16 Mar 2019 16:17:25 -0700 Subject: [PATCH 12/16] Update content/docs/hooks-faq.md --- content/docs/hooks-faq.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/hooks-faq.md b/content/docs/hooks-faq.md index cba39df24..c272619c4 100644 --- a/content/docs/hooks-faq.md +++ b/content/docs/hooks-faq.md @@ -538,7 +538,7 @@ function ProductPage({ productId }) { } ``` -**Рекомендованное исправлять такой код, перемещая функцию _внутрь_ вашего эффекта**. Это помогает замечать, какие пропсы и состояние используются вашим эффектом, и убедиться, что они перечислены в списке зависимостей: +**Рекомендовано исправлять такой код, перемещая функцию _внутрь_ вашего эффекта**. Это помогает замечать, какие пропсы и состояние используются вашим эффектом, и убедиться, что они перечислены в списке зависимостей: ```js{5-10,13} function ProductPage({ productId }) { From 06139a5a524850f5ea21133b78193edac1f40c30 Mon Sep 17 00:00:00 2001 From: Nick Tishkevich Date: Sat, 16 Mar 2019 16:17:52 -0700 Subject: [PATCH 13/16] Update content/docs/hooks-faq.md Co-Authored-By: another-guy --- content/docs/hooks-faq.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/hooks-faq.md b/content/docs/hooks-faq.md index c272619c4..ccfad9718 100644 --- a/content/docs/hooks-faq.md +++ b/content/docs/hooks-faq.md @@ -404,7 +404,7 @@ function Example() { Если вы намеренно хотите считать из асинхронного колбэка *свежайшее* состояние, вы можете сперва сохранить его [в реф](/docs/hooks-faq.html#is-there-something-like-instance-variables), потом изменить его и затем считать его из рефа. -Наконец, возможна другая ситуация, почему вы видите устаревшие пропсы или состояние: когда вы используете оптимизацию с помощью "массива зависимостей", но неправильно указали какие-то зависимости. Например, если эффект передаёт вторым параметром `[]`, но при этом использует `someProp`, то он продолжит "видеть" исходное значение `someProp`. Правильным решением является либо исправление массива, либо отказ от его использования. +Наконец, возможна другая ситуация, почему вы видите устаревшие пропсы или состояние: когда вы используете оптимизацию с помощью «массива зависимостей», но неправильно указали какие-то зависимости. Например, если эффект передаёт вторым параметром `[]`, но при этом использует `someProp`, то он продолжит «видеть» исходное значение `someProp`. Правильным решением является либо исправление массива, либо отказ от его использования. По этим ссылкам описаны [подходы к функциям](#is-it-safe-to-omit-functions-from-the-list-of-dependencies) в аналогичных ситуациях и [другие известные способы](#what-can-i-do-if-my-effect-dependencies-change-too-often) снижения частоты вызова эффектов, исключающие передачу неправильных зависимостей. >Примечание From a51748827d525fd0c52dd24413e4978140cabac0 Mon Sep 17 00:00:00 2001 From: Nick Tishkevich Date: Sat, 16 Mar 2019 16:20:51 -0700 Subject: [PATCH 14/16] Update content/docs/hooks-faq.md Co-Authored-By: another-guy --- content/docs/hooks-faq.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/hooks-faq.md b/content/docs/hooks-faq.md index ccfad9718..fb3351433 100644 --- a/content/docs/hooks-faq.md +++ b/content/docs/hooks-faq.md @@ -374,7 +374,7 @@ function Counter() { ### Почему я вижу устаревшие пропсы или состояние в моей функции? {#why-am-i-seeing-stale-props-or-state-inside-my-function} -Любая функция внутри компонента, включая эффекты и обработчики событий, "видит" пропсы и состояние из функции `render()`, в которой она была создана. Рассмотрим такой код: +Любая функция внутри компонента, включая эффекты и обработчики событий, «видит» пропсы и состояние из функции `render()`, в которой она была создана. Рассмотрим такой код: ```js function Example() { From 986fdc62b98a2a0f12f0feec23aa3e6e2997620e Mon Sep 17 00:00:00 2001 From: Vlad Date: Sat, 16 Mar 2019 16:25:06 -0700 Subject: [PATCH 15/16] Update content/docs/hooks-effect.md Co-Authored-By: another-guy --- content/docs/hooks-effect.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/hooks-effect.md b/content/docs/hooks-effect.md index 03a75df56..9b9fb1500 100644 --- a/content/docs/hooks-effect.md +++ b/content/docs/hooks-effect.md @@ -473,7 +473,7 @@ useEffect(() => { > >Если вы хотите использовать эту оптимизацию, обратите внимание на то, чтобы массив включал в себя **все значения из области видимости компонента (такие как пропсы и состояние), которые могут изменяться с течением времени, и которые будут использоваться эффектом**. В противном случае, ваш код будет ссылаться на устаревшее значение из предыдущих рендеров. Отдельные страницы документации рассказывают о том, [как поступить с функциями](/docs/hooks-faq.html#is-it-safe-to-omit-functions-from-the-list-of-dependencies) и [что делать с часто изменяющимися массивами](/docs/hooks-faq.html#what-can-i-do-if-my-effect-dependencies-change-too-often). > ->Если вы хотите выполнять эффект и сбрасывать его однократно (при монтировании и размонтировании), вы можете передать пустой массив (`[]`) вторым аргументом. React посчитает, что ваш эффект не зависит от *каких-либо* значений из пропсов или состояния и поэтому не будет выполнять повторных рендеров. Это не расценивается как особый случай -- он напрямую следует из логики работы входных массивов. +>Если вы хотите запустить эффект и сбросить его только один раз (при монтировании и размонтировании), вы можете передать пустой массив (`[]`) вторым аргументом. React посчитает, что ваш эффект не зависит от *каких-либо* значений из пропсов или состояния и поэтому не будет выполнять повторных рендеров. Это не обрабатывается как особый случай -- он напрямую следует из логики работы входных массивов. > >Если вы передадите пустой массив (`[]`), пропсы и состояние внутри эффекта всегда будут иметь значения, присвоенные им изначально. Хотя передача `[]` ближе по модели мышления к знакомым `componentDidMount` и `componentWillUnmount`, обычно есть [более хорошие](/docs/hooks-faq.html#is-it-safe-to-omit-functions-from-the-list-of-dependencies) [способы](/docs/hooks-faq.html#what-can-i-do-if-my-effect-dependencies-change-too-often) избежать частых повторных рендеров. Не забывайте, что React откладывает выполнение `useEffect`, пока браузер не отрисует все изменения, поэтому выполнение дополнительной работы не является существенной проблемой. > From 8e9a4a1eb78a04792098f036e27adc95aa0f45ef Mon Sep 17 00:00:00 2001 From: Igor Soloydenko Date: Sat, 16 Mar 2019 21:44:45 -0700 Subject: [PATCH 16/16] Rename parameter --- content/docs/hooks-reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/hooks-reference.md b/content/docs/hooks-reference.md index 8bf55fa5f..363715946 100644 --- a/content/docs/hooks-reference.md +++ b/content/docs/hooks-reference.md @@ -298,7 +298,7 @@ const memoizedCallback = useCallback( Передайте встроенный колбэк и массив зависимостей. Хук `useCallback` вернёт запомненную версию колбэка, который изменяется только в случае изменения значения одной из зависимостей. Это полезно при передаче колбэков оптимизированным дочерним компонентам, которые полагаются на равенство ссылок для предотвращения ненужных рендеров (например, `shouldComponentUpdate`). -`useCallback(fn, inputs)` – это эквивалент `useMemo(() => fn, inputs)`. +`useCallback(fn, deps)` – это эквивалент `useMemo(() => fn, deps)`. > Примечание >