diff --git a/content/community/conferences.md b/content/community/conferences.md index e138b119a..ea8613c78 100644 --- a/content/community/conferences.md +++ b/content/community/conferences.md @@ -57,6 +57,11 @@ July 15-21, 2019. New York City, USA [Website](https://reactweek.nyc) - [Twitter](https://twitter.com/ReactWeek) +### React Rally 2019 +August 22-23, 2019. Salt Lake City, USA. + +[Website](https://www.reactrally.com/) - [Twitter](https://twitter.com/ReactRally) - [Instagram](https://www.instagram.com/reactrally/) + ### ComponentsConf 2019 {#componentsconf-2019} September 6, 2019 in Melbourne, Australia [Website](https://www.componentsconf.com.au/) - [Twitter](https://twitter.com/componentsconf) diff --git a/content/docs/hooks-faq.md b/content/docs/hooks-faq.md index fc404e0c2..580884286 100644 --- a/content/docs/hooks-faq.md +++ b/content/docs/hooks-faq.md @@ -41,6 +41,7 @@ prev: hooks-reference.html * [Как я могу реализовать `getDerivedStateFromProps`?](#how-do-i-implement-getderivedstatefromprops) * [Существует что-нибудь наподобие forceUpdate?](#is-there-something-like-forceupdate) * [Могу ли я изменить реф, переданный в функциональный компонент?](#can-i-make-a-ref-to-a-function-component) + * [Как я могу измерить узел DOM?](#how-can-i-measure-a-dom-node) * [Что значит `const [thing, setThing] = useState()`?](#what-does-const-thing-setthing--usestate-mean) * [Оптимизации производительности](#performance-optimizations) * [Могу ли я пропустить эффект при обновлениях?](#can-i-skip-an-effect-on-updates) @@ -403,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) снижения частоты вызова эффектов, исключающие передачу неправильных зависимостей. >Примечание @@ -451,9 +452,62 @@ function ScrollView({row}) { ### Могу ли я изменить реф, переданный в функциональный компонент? {#can-i-make-a-ref-to-a-function-component} - Несмотря на то, что вам не понадобится это часто, вы можете предоставить некоторые императивные методы родительскому компоненту, используя хук [`useImperativeHandle`](/docs/hooks-reference.html#useimperativehandle). +### Как я могу измерить узел DOM? {#how-can-i-measure-a-dom-node} + +Для определения положения или размера DOM-узла можно использовать [колбэк-реф](/docs/refs-and-the-dom.html#callback-refs). React будет вызывать этот колбэк всякий раз, когда реф привязывается к другому узлу. Вот [небольшая демонстрация](https://codesandbox.io/s/l7m0v5x4v9): + +```js{4-8,12} +function MeasureExample() { + const [height, setHeight] = useState(0); + + const measuredRef = useCallback(node => { + if (node !== null) { + setHeight(node.getBoundingClientRect().height); + } + }, []); + + return ( + <> +

Привет, мир

+

Заголовок выше имеет высоту {Math.round(height)} пикселей

+ + ); +} +``` + +Мы не выбрали `useRef` в этом примере, потому что объект рефа не уведомляет нас об *изменениях* текущего значения рефа. Использование колбэк-рефа гарантирует, что [даже если дочерний компонент отображает измеренный узел позже](https://codesandbox.io/s/818zzk8m78) (например, в ответ на клик), мы по-прежнему получаем уведомление об этом в родительском компоненте и можем обновлять измерения. + +Обратите внимание, что мы передаем `[]` как массив зависимостей в `useCallback`. Это гарантирует, что наш колбэк-реф не изменится между повторными рендерами, а значит React не будет вызывать его без необходимости. + +При желании вы можете [извлечь эту логику](https://codesandbox.io/s/m5o42082xy) в переиспользуемый хук: + +```js{2} +function MeasureExample() { + const [rect, ref] = useClientRect(); + return ( + <> +

Привет, мир

+ {rect !== null && +

Заголовок выше имеет высоту {Math.round(height)} пикселей

+ } + + ); +} + +function useClientRect() { + const [rect, setRect] = useState(null); + const ref = useCallback(node => { + if (node !== null) { + setRect(node.getBoundingClientRect()); + } + }, []); + return [rect, ref]; +} +``` + + ### Что значит `const [thing, setThing] = useState()`? {#what-does-const-thing-setthing--usestate-mean} Если вы не знакомы с этим синтаксисом, ознакомьтесь с [объяснением](/docs/hooks-state.html#tip-what-do-square-brackets-mean) в документации хука состояния. @@ -857,8 +911,8 @@ function Form() { const [text, updateText] = useState(''); const textRef = useRef(); - useLayoutEffect(() => { - textRef.current = text; // Записать в реф + useEffect(() => { + textRef.current = text; // Записать это в реф }); const handleSubmit = useCallback(() => { @@ -898,7 +952,7 @@ function useEventCallback(fn, dependencies) { throw new Error('Невозможно вызвать обработчик события во время рендера.'); }); - useLayoutEffect(() => { + useEffect(() => { ref.current = fn; }, [fn, ...dependencies]); diff --git a/content/docs/hooks-reference.md b/content/docs/hooks-reference.md index 1029e0646..66a79ab48 100644 --- a/content/docs/hooks-reference.md +++ b/content/docs/hooks-reference.md @@ -96,6 +96,8 @@ const [state, setState] = useState(() => { Если вы обновите состояние хука тем же значением, что и текущее состояние, React досрочно выйдет из хука без повторного рендера дочерних элементов и запуска эффектов. (React использует [алгоритм сравнения `Object.is`](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Object/is#Description).) +Обратите внимание, что для React всё еще может быть необходим повторный рендер этого компонента. Это не должно быть проблемой, потому что React не будет сильно «углубляться» в дерево. Если вы делаете дорогостоящие вычисления во время рендеринга, вы можете оптимизировать их с помощью `useMemo`. + ### `useEffect` {#useeffect} ```js @@ -171,12 +173,28 @@ useEffect( ### `useContext` {#usecontext} ```js -const context = useContext(Context); +const value = useContext(MyContext); ``` -Принимает объект контекста (значение, возвращённое из `React.createContext`) и возвращает текущее значение контекста, как указано ближайшим поставщиком контекста для данного контекста. +Принимает объект контекста (значение, возвращаемое из `React.createContext`) и возвращает текущее значение контекста для этого контекста. Текущее значение контекста определяется пропом `value` ближайшего `` над вызывающим компонентом в дереве. + +Когда ближайший `` над компонентом обновляется, этот хук вызовет повторный рендер с последним значением контекста, переданным этому провайдеру `MyContext`. + +Запомните, аргумент для `useContext` должен быть *непосредственно сам объект контекста*: + + * **Правильно:** `useContext(MyContext)` + * **Неправильно:** `useContext(MyContext.Consumer)` + * **Неправильно:** `useContext(MyContext.Provider)` + -Когда провайдер обновляется, этот хук инициирует повторный рендер с последним значением контекста. +Компонент, вызывающий `useContext`, всегда будет перерендериваться при изменении значения контекста. Если повторный рендер компонента затратен, вы можете [оптимизировать его с помощью мемоизации](https://github.com/facebook/react/issues/15156#issuecomment-474590693). + +>Совет +> + +>Если вы были знакомы с API контекстов до появления хуков, то вызов `useContext(MyContext)` аналогичен выражению `static contextType = MyContext` в классе, либо компоненту ``. +> +>`useContext (MyContext)` позволяет только *читать* контекст и подписываться на его изменения. Вам всё ещё нужен `` выше в дереве, чтобы *предоставить* значение для этого контекста. ## Дополнительные хуки {#additional-hooks} @@ -283,6 +301,8 @@ function Counter({initialCount}) { Если вы вернёте то же значение из редюсера хука, что и текущее состояние, React выйдет без перерисовки дочерних элементов или запуска эффектов. (React использует [алгоритм сравнения Object.is](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Object/is#Description).) +Обратите внимание, что для React всё еще может быть необходим повторный рендер этого компонента. Это не должно быть проблемой, потому что React не будет сильно «углубляться» в дерево. Если вы делаете дорогостоящие вычисления во время рендеринга, вы можете оптимизировать их с помощью `useMemo`. + ### `useCallback` {#usecallback} ```js @@ -354,7 +374,16 @@ function TextInputWithFocusButton() { } ``` -Обратите внимание, что `useRef()` полезен не только для атрибута `ref`. Он также [удобен для хранения любого изменяемого значения](/docs/hooks-faq.html#is-there-something-like-instance-variables) примерно так же, как вы используете поля экземпляров в классах. +По сути, `useRef` похож на «коробку», которая может содержать изменяемое значение в своём свойстве `.current`. + +Возможно, вы знакомы с рефами в основном как со способом [получить доступ к DOM](/docs/refs-and-the-dom.html). Если вы передадите React объект рефа с помощью подобного выражения `
`, React установит собственное свойство `.current` на соответствующий DOM-узел при каждом его изменении. + +Но хук `useRef()` полезен не только установкой атрибута с рефом. Он [удобен для сохранения любого мутируемого значения](/docs/hooks-faq.html#is-there-something-like-instance-variables), по аналогии с тем, как вы используете поля экземпляра в классах. + +Это возможно, поскольку `useRef()` создаёт обычный JavaScript-объект. Единственная разница между `useRef()` и просто созданием самого объекта `{current: ...}` — это то, что хук `useRef` даст один и тот же объект с рефом при каждом рендере. + +Имейте в виду, что `useRef` *не* уведомляет вас, когда изменяется его содержимое. Мутирование свойства `.current` не вызывает повторный рендер. Если вы хотите запустить некоторый код, когда React присоединяет или отсоединяет реф к узлу DOM, вы можете использовать [колбэк-реф](/docs/hooks-faq.html#how-can-i-measure-a-dom-node) вместо этого. + ### `useImperativeHandle` {#useimperativehandle} @@ -387,7 +416,11 @@ FancyInput = forwardRef(FancyInput); > Совет > -> Если вы переносите код из классового компонента, `useLayoutEffect` запускается в той же фазе, что и `componentDidMount` и `componentDidUpdate`, поэтому, если вы не уверены, какой хук эффект использовать, это, вероятно, наименее рискованно. +> Если вы переносите код из классового компонента, `useLayoutEffect` запускается в той же фазе, что и `componentDidMount` и `componentDidUpdate`. Тем не менее, *мы рекомендуем начать с `useEffect`**, и попробовать использовать `useLayoutEffect`, если тот приводит к возникновению проблем. +> +>Если вы используете серверный рендеринг, имейте в виду, что *ни* `useLayoutEffect`, ни `useEffect` не могут работать до загрузки JavaScript. Вот почему React предупреждает, когда серверный компонент содержит `useLayoutEffect`. Чтобы справиться с данной проблемой, либо переместите эту логику в `useEffect` (если она не нужна для первого рендера), либо задержите отображение этого компонента до тех пор, пока не выполнится рендеринг на стороне клиента (если HTML некорректный до запуска `useLayoutEffect`). +> +>Чтобы исключить компонент, который нуждается в эффектах макета из HTML-кода, полученного в результате серверного рендеринга, выполните его рендер по условию `showChild && ` и отложите отображение с помощью `useEffect(() => { setShowChild(true); }, [])``. Таким образом, пользовательский интерфейс не будет выглядеть некорректно перед гидратацией. ### `useDebugValue` {#usedebugvalue} diff --git a/content/languages.yml b/content/languages.yml index 5e0958260..524c41c73 100644 --- a/content/languages.yml +++ b/content/languages.yml @@ -66,11 +66,15 @@ - name: Italian translated_name: Italiano code: it - status: 0 + status: 1 - name: Japanese translated_name: 日本語 code: ja status: 2 +- name: Georgian + translated_name: ქართული + code: ka + status: 0 - name: Central Khmer translated_name: ភាសាខ្មែរ code: km @@ -126,6 +130,7 @@ - name: Swedish translated_name: Svenska code: sv + status: 0 - name: Tamil translated_name: தமிழ் code: ta @@ -134,6 +139,10 @@ translated_name: తెలుగు code: te status: 0 +- name: Thai + translated_name: ไทย + code: th + status: 0 - name: Turkish translated_name: Türkçe code: tr @@ -157,7 +166,7 @@ - name: Simplified Chinese translated_name: 简体中文 code: zh-hans - status: 1 + status: 2 - name: Traditional Chinese translated_name: 繁體中文 code: zh-hant