Hook
Если вы хорошо разбираетесь в React Hook, этой статьи достаточно.
Эта статья расскажет вам о повседневном использовании и расширенных операциях 9 React Hooks, а также о том, как полностью освоить React Hook от простого до глубокого!
useState
Если вы мало что знаете об использовании useState, вы можете переместитьРеагировать на китайскую документацию, который похож на this.setState в компоненте класса.
когда мы используем
useState
Когда переменная состояния определена, она возвращает массив с двумя значениями. Первое значение — это текущее состояние, а второе значение — это функция, которая обновляет состояние.
Так называемое государственное закрытие
Что касается замыкания, сгенерированного useState, давайте посмотрим на этот фрагмент кода:
import React, { useState } from 'react'
const DemoState: React.FC = () => {
const [count, setCount] = useState(0)
const handleClickBtn = () => {
setCount(count + 1)
}
const handleAlert = () => {
setTimeout(() => {
alert(count)
}, 3000)
}
return <div>
<div style={{ margin: '20px' }}>
<button onClick={handleClickBtn}>Click Me !</button>
</div>
<p onClick={handleAlert}>This is Count: {count}</p>
</div>
}
export {
DemoState
}
Страница будет отображать:
-
Кнопка, когда мы нажимаем кнопку, значение счетчика будет увеличиваться на единицу.
-
Тег p, когда мы щелкаем тег p, таймер распечатывает значение count через 3 с.
Далее давайте сделаем что-то вроде этого:
Нажмите на вкладку P и быстро нажмите Click Me три раза! Позже. На данный момент значение count было обновлено до 3 на странице, но печать в setTimeout через 3 с по-прежнему будет равна 0.
На самом деле, когда функция DemoState запускается каждый раз, когда мы вызываем ее при каждом рендеринге, каждая функция рендеринга имеет свои собственные независимые реквизиты и состояние.Когда состояние в коде вызывается в jsx для рендеринга, каждый рендеринг получит свой собственный рендеринг. и государство.
Таким образом, когда таймер срабатывает, полученное значение счетчика является внутренним значением счетчика, когда функция DemoState отображается в первый раз из-за закрытия, и неудивительно, что результат предупреждения равен 0.
Если вы все еще не понимаете основной контент здесь, вы можете двигаться дальше.Проработка useRef в React.
Так называемый принцип пакетного обновления
Студенты, знакомые с React, знают, что так называемые изменения состояния следуют внутри React.Массовое обновлениев общем.
Так называемый асинхронный пакет означает, что если в обновлении страницы участвует несколько изменений состояния, результаты нескольких изменений состояния будут объединены для получения окончательного результата, и будет выполнено обновление страницы.
Что касается принципа пакетного обновления, то он есть только всинтетическое событиеВ состоянии isBatchUpdating будут включены пакетные обновления. Простыми словами».
-
все
React
Там, где это можно контролировать, это асинхронное пакетное обновление.. Например, функции событий, функции жизненного цикла и код синхронизации внутри компонентов. -
все
React
Место, которое нельзя контролировать, — это синхронное пакетное обновление.. НапримерsetTimeout
,setInterval
,源生DOM
в случае,включатьPromise
серединаВсе синхронные пакетные обновления.
В React 18 обработчики внешних событий обрабатываются пакетами в createRoot, Другими словами, в последнем React неуправляемые места, такие как setTimeout и setInterval, стали пакетными обновлениями.
Что касается синтетических событий и пакетных обновлений, вы можетеКопаем глубже в состояние в ReactЭта статья.
Реализовать использованиеSetState
Передача поддерживается в this.setState в компоненте класса.Объединить входящие параметры setState, в useState, если передается тип объекта, он будет перезаписан.
Если нам нужно реализовать это требование в useState, мы можем сделать это, обернув дополнительный хук useSetState:
import { useCallback, useState } from 'react';
function useSetState<T extends {}>(
initialState: T = {} as T
): [T, (patch: Partial<T> | ((prevState: T) => Partial<T>)) => void] {
const [state, set] = useState<T>(initialState);
const setState = useCallback((patch) => {
set((preState) =>
Object.assign(
{},
preState,
typeof patch === 'function' ? patch(preState) : patch
)
);
}, []);
return [state, setState];
}
export default useSetState;
вы можете нажать на этоАдрес CodeSandBoxСм. конкретные примеры.
useEffect
useEffect называется хуком побочного эффекта, а этот хук — базовым хуком, таким как useState. Хуки эффектов позволяют выполнять побочные эффекты в функциональных компонентах.
useEffect Hook поддерживает два параметра, первый параметр — это функция, представляющая функцию побочного эффекта, которая по умолчанию будет выполняться после первого рендеринга и после каждого обновления.
Второй аргумент — это массив, определяющий зависимости первого аргумента (функция побочного эффекта). Функция побочного эффекта будет выполняться только в том случае, если переменные в этом массиве изменятся.
Что касается хука useEffect, вы можете обратиться к более простому использованию.Реагировать на официальную документациюСодержание использования Defeffect все еще более всеобъемлющее в документе, я не буду громоздким.
Реализовать useUpdateEffect
В компоненте Class есть жизненный цикл componentDidUpdate. Он будет вызываться сразу после обновления, первый рендер не будет выполнять этот метод.
В Function Component мы можем реализовать функцию componentDidUpdate с помощью дополнительной инкапсуляции useEffect:
Во-первых, мы можем реализовать хук, который определяет, является ли это первым рендерингом через useRef:
import { useRef } from 'react';
export function useFirstMountState(): boolean {
const isFirst = useRef(true);
if (isFirst.current) {
isFirst.current = false;
return true;
}
return isFirst.current;
}
Если вы не знаете, в частности, роль useRef, не беда, позже я познакомлю вас с его механизмом в деталях. Здесь вам нужно только знать, что хук useFirstMountState вернет true при первом рендеринге компонента и false в остальных случаях.
Следующий шаг очень прост: с помощью useFirstMountState мы можем определить, отображается ли страница в первый раз. Тогда вам нужно только судить, является ли это первым обновлением в Эффекте:
import { useEffect } from 'react';
import { useFirstMountState } from './useFirstMountState';
const useUpdateEffect: typeof useEffect = (effect, deps) => {
const isFirstMount = useFirstMountState();
useEffect(() => {
if (!isFirstMount) {
return effect();
}
}, deps);
};
export default useUpdateEffect;
useContext
Контекст предоставляет способ обмена такими значениями между компонентами без необходимости явно передавать свойства вниз по дереву компонентов.
Учащиеся, знакомые с Context Api в React и предоставляющие/внедряющие API в Vue, могут иметь глубокое понимание роли этого хука.
Допустим такой сценарий:
В компоненте корневого уровня нам нужно передать атрибут имени пользователя для каждого используемого дочернего компонента.
На этом этапе, если вы используете метод props для прохождения слой за слоем, это, несомненно, будет кошмаром. И если наш компонент G должен использовать имя пользователя, а B и E — нет, то неизбежно явное объявление имени пользователя внутри компонентов B и E, если используется метод props.
В React для решения такого сценария предлагается Context Api.
Вы можете создать объект контекста через React.createContext, передать имя пользователя через свойство значения Context.Provider в компоненте и использовать useContext(Context) в функциональном компоненте, чтобы получить соответствующее значение.
useContext (MyContext), чтобы вы могли прочитать изменение значения контекста и контекста подписки. Вам по-прежнему необходимо использовать
в верхнем дереве компонентов, чтобы предоставить контекст для базовых компонентов.
Подробное использование Context && useContext может бытьпроверить здесь, конкретный API получил очень подробное описание на официальном сайте.
useReducer
Выше мы упомянули базовый хук управления состоянием useState, а в React Hook предоставляется дополнительный useReducer для управления состоянием.
использование useReducer
const [state, dispatch] = useReducer(reducer, initialArg, init);
useReducer принимает три параметра: функцию редуктора, начальное значение initialArg и необязательную функцию инициализации с ленивой инициализацией.
Он получает(state, action) => newState
Редуктор и возвращает текущее состояние и его соответствиеdispatch
метод.
Давайте посмотрим на его основное использование на простом встречном примере:
import { useReducer } from 'react';
interface IState {
count: number;
}
interface IAction {
type: 'add' | 'subtract';
payload: number;
}
const initialState: IState = { count: 0 };
const reducer = (state: IState, action: IAction) => {
switch (action.type) {
case 'add':
return { count: state.count + action.payload };
case 'subtract':
return { count: state.count - action.payload };
default:
throw new Error('Illegal operation in reducer.');
}
};
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
<h1>Hello , My name is 19Qingfeng.</h1>
<p>Counter: {state.count}</p>
<p>
<button onClick={() => dispatch({ type: 'add', payload: 1 })}>
add 1!
</button>
</p>
<p>
<button onClick={() => dispatch({ type: 'subtract', payload: 1 })}>
subtract 1!
</button>
</p>
</>
);
}
export default Counter;
Здесь мы создаем простой компонент счетчика, который внутренне управляет состоянием счетчика через useReducer.
ты сможешьздесьДавайте рассмотрим этот небольшой контрпример.
useState & useReducer
Небольшой встречный пример выше на самом деле может быть достигнут с помощью setState.У большинства студентов должен возникнуть такой вопрос при написании компонентов:
«Когда использовать useState и когда использовать useReducer, каковы преимущества/недостатки useReducer по сравнению с useState?»
На самом деле использование useState в большинстве повседневных ситуаций вполне может соответствовать роли ежедневной разработки, ведь если использовать action -> reducer -> store для управления состоянием для простой операции, то это немного перебор.
В большинстве статей о том, следует ли использовать useState или useReducer для управления состоянием, будет сказано, что useReducer подходит для сложной логики состояния.
Правильно, я также использую его в повседневных приложениях.Когда есть несколько сложных управлений состоянием, функция редуктора используется для отправки обновлений состояния в соответствии с различными действиями.
Но опять же, если в состоянии много состояний операций, и каждая операция имеет много логики, для такого сложного состояния использование useState для управления отдельной функцией может отличаться от использования нескольких разных действий в одной функции в редуктор более четко.
Что касается «когда использовать useState и когда использовать useReducer», по моему личному мнению, использование этих двух методов больше похоже на компромисс.В общем, старайтесь использовать метод, который вам удобен и который легче понять вам и вашим коллегам.
Глубоко обновленные компоненты для оптимизации производительности
В официальной документации useReducer есть такое введение:
и, используя
useReducer
Он также может выполнять оптимизацию производительности для компонентов, которые запускают глубокие обновления, потому что вы можете передать его дочерним компонентам.dispatch
вместо функции обратного вызова
В некоторых сценариях мы обычно передаем функции в качестве свойств дочерним компонентам, так что каждый раз, когда родительский компонент перерисовывается, даже если мы не модифицируем функцию как свойства, дочерний компонент будет повторно отображаться.
Давайте посмотрим на этот пример:
// 父组件
import { useState } from 'react';
import ChildComponent from './Child';
function ParentComponent() {
const [count, setCount] = useState(0);
const callback = () => {
return 10;
};
return (
<div>
<h3>Hello This is Parent Component!</h3>
<p>ParentCount: {count}</p>
<button onClick={() => setCount(count + 1)}>Click Me!</button>
<br />
<ChildComponent callback={callback} />
</div>
);
}
export default ParentComponent;
// 子组件
import React, { FC, useEffect } from 'react';
interface Props {
callback?: () => number;
}
const ChildComponent: FC<Props> = ({ callback }) => {
useEffect(() => {
alert('child re-render');
}, [callback]);
return (
<>
<h1>Hello This is Child Component</h1>
<p>{callback && callback()}</p>
</>
);
};
export default ChildComponent;
Здесь мы передаем функцию обратного вызова в качестве реквизита в родительском компоненте дочернему компоненту, когда мы нажимаем кнопку на странице, чтобы увидеть, что происходит:
Каждый раз, когда нажимается кнопка родительского компонента, выполняется эффект в дочернем компоненте.
На данный момент обратный вызов, который мы передали в подкомпонент, не изменился, и мы, естественно, ожидаем, что Эффект в подкомпоненте не будет выполнен.
Механизм для этого заключается в том, что React повторно выполняет функцию компонента каждый раз при его рендеринге и повторно генерирует функцию обратного вызова при повторном выполнении родительского компонента. Поскольку React использует Object.is внутри, React будет думать, что свойства дочернего компонента изменились.
Вы можете нажать здесь, чтобы просмотретьПример CodeSandBox
Отправка, возвращаемая в useReduce, — это просто функция, но одно из преимуществ useReducer заключается в том, что отправка не будет перераспределять место в памяти при повторном рендеринге.Например, когда мы передаем отправку в качестве реквизита дочернему компоненту, дочерний компонент Эффект in также не выполняется.
Заинтересованные студенты могут попробовать это в частном порядке.Конечно, использование useCallback, включая функции родительского компонента в нашей демонстрации выше, также может достичь того же эффекта, но это означает, что у нас есть много обратных вызовов, которые нужно привязать к useCallback. не очень хорошая вещь.
useCallback
Далее поговорим об useCallback, его самая большая роль отражена в оптимизации производительности в React.
Как обычно, давайте сначала рассмотрим основное использование:
const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b],
);
useCallback принимает два параметра:
-
Первый параметр — это функция, которая будет перегенерирована только после изменения соответствующей зависимости, или эта функция генерируется «в памяти».
-
Второй параметр — это массив, представляющий зависимости, от которых зависит первый параметр, и функция первого параметра будет только «очищать память» и перегенерировать, если элемент в массиве изменится.
Возможно, большинству друзей, знакомых с React, будет любопытен сценарий использования этого хука, а пока давайте вспомним пример, упомянутый в главе useReducer.
Мы передаем функцию обратного вызова в родительском компоненте в качестве реквизита для дочернего компонента.Мы не меняем обратный вызов при каждом рендеринге, но каждый раз, когда родительский компонент выполняет повторную визуализацию, React по-прежнему считает, что обратный вызов изменился, что приводит к тому, что избыточные дочерние компоненты повторно рендерить.
Если вы забыли этот пример, вы можете обратиться к разделу useReducer, чтобы просмотреть его еще раз.
На данный момент использование useCallback может очень хорошо решить этот пример.
Давайте немного изменим код в родительском компоненте выше:
import { useCallback, useState } from 'react';
import ChildComponent from './Child';
function ParentComponent() {
const [count, setCount] = useState(0);
// 这里我们使用了 useCallback 进行包裹
const callback = useCallback(() => {
return 10;
}, []);
return (
<div>
<h3>Hello This is Parent Component!</h3>
<p>ParentCount: {count}</p>
<button onClick={() => setCount(count + 1)}>Click Me!</button>
<br />
<ChildComponent callback={callback} />
</div>
);
}
export default ParentComponent;
Вы можете видеть, что мы используем useCallback для переноса функции обратного вызова, переданной в дочерний компонент, при этом передавая пустой массив в качестве второго параметра зависимости.
Теперь давайте посмотрим на эффект отображения страницы:
В этот момент, даже если мы нажмем кнопку несколько раз, эффект дочернего компонента не будет выполнен.
вы можете нажатьПроверьте CodeSandBox здесь.
useMemo
функция useMemo
Если useCallback — это то, что команда React предоставляет разработчикам в качестве оптимизации для функций, то useMemo можно рассматривать как способ «запоминания» значений для оптимизации производительности.
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
useMemo также является хуком, предоставляемым для оптимизации производительности.По сравнению с useCallback, он поддерживает возможность запоминания любого типа значения.
Также он поддерживает два параметра:
-
Первый параметр принимает функцию, и возвращаемое значение входящего вызова функции будет «запоминаться». Только когда зависимости изменятся, переданная функция будет повторно вычислять новый возвращаемый результат.
-
Второй параметр также представляет собой массив, представляющий зависимости, соответствующие первому параметру.
Давайте рассмотрим такой пример:
import React, { useState } from 'react';
const data = [
{ name: '数学', id: 0 },
{ name: '语文', id: 1 },
{ name: '英语', id: 2 },
{ name: '化学', id: 3 },
{ name: '生物', id: 4 },
];
function Demo(): React.ReactElement {
const [count, setCount] = useState(0);
const renderSubject = (() => {
console.log('Recalculate renderSubject !');
return data.map((i) => <li key={i.id}>{i.name}</li>);
})();
return (
<div>
<p>count: {count}</p>
<button onClick={() => setCount(count + 1)}>Click Me !</button>
<br />
<h1>科目:</h1>
<ul>{renderSubject}</ul>
</div>
);
}
export default Demo;
Каждый раз, когда мы нажимаем кнопку повторного рендеринга компонента, значение renderSubject будет пересчитываться, что означает, что оно будет печататься каждый раз.Recalculate renderSubject !
.
На этом этапе давайте обернем renderSubject с помощью useMemo и скажем React «запомнить» значение renderSubject и попробовать еще раз:
import React, { useMemo, useState } from 'react';
const data = [
{ name: '数学', id: 0 },
{ name: '语文', id: 1 },
{ name: '英语', id: 2 },
{ name: '化学', id: 3 },
{ name: '生物', id: 4 },
];
function Demo(): React.ReactElement {
const [count, setCount] = useState(0);
const renderSubject = useMemo(() => {
return (() => {
console.log('Recalculate renderSubject !');
return data.map((i) => <li key={i.id}>{i.name}</li>);
})();
}, []);
return (
<div>
<p>count: {count}</p>
<button onClick={() => setCount(count + 1)}>Click Me !</button>
<br />
<h1>科目:</h1>
<ul>{renderSubject}</ul>
</div>
);
}
export default Demo;
В этот момент, когда мы нажимаем кнопку на странице, счетчик изменяется при повторном рендеринге страницы, потому что мы возвращаем его в функцию, переданную с помощью useMemo.data.map((i) => <li key={i.id}>{i.name}</li>)
И второй параметр — это пустой массив.
Независимо от того, как повторно отображается страница, значение, возвращаемое в useMemo, не будет пересчитываться до тех пор, пока зависимости не изменятся.
Пример кода в статье специально разработан, чтобы показать роль хука, здесь каждый может понять смысл, который нужно выразить.
Что я хочу сказать об оптимизации производительности
И useCallback, и useMemo Hooks — это методы, которые React предоставляет разработчикам в качестве средства оптимизации производительности.
Но в большинстве случаев вам не нужно думать об оптимизации ненужных повторных рендеров.. React работает очень быстро, и я могу придумать много вещей, которые вы можете сделать со своим временем, которые намного лучше, чем такие оптимизации.
Что касается useCallback и useMemo, я лично считаю, что неразумное использование этих двух хуков не только усложнит код, но и может помешать сборке мусора зависимостей и мемоизированных значений путем вызова встроенного хука, что приведет к плохой производительность. .
Если в некоторых случаях, таких как диаграммы, анимация и т. д. с особенно сложными взаимодействиями, использование этих двух хуков может дать вам необходимые преимущества в производительности, то эти затраты стоят того, чтобы их нести, ноЛучше всего измерить перед использованием.
В официальной документации указано, чтоНе нужно беспокоиться о создании функций, вызывающих проблемы с производительностью.. Приведенные выше примеры предназначены только для того, чтобы показать вам, как их использовать, и не рекомендуется использовать их в реальных сценариях.
Для неправильного понимания использования useCallback и useMemo вы можете проверить эту статьюНеправильное понимание useCallback/useMemo
useRef
Есть две основные функции useRef Hook:
- Связь, которая гарантирует уникальные значения между несколькими рендерами.
useRef сохранит уникальную ссылку на возвращаемое значение для всех рендеров. потому что всеref
Назначение и значение get являются конечным состоянием, и нет другой изоляции из-за разных рендеров.
Мы показали пример этого в хуке useEffect в начале, чтобы определить, связано ли это с обновлением страницы, а не с первым рендерингом:
import { useRef } from 'react';
export function useFirstMountState(): boolean {
const isFirst = useRef(true);
if (isFirst.current) {
isFirst.current = false;
return true;
}
return isFirst.current;
}
- Чтобы получить элемент Dom, в функциональном компоненте мы можем использовать useRef для получения соответствующего элемента Dom.
О роли и использовании useRef я в этой статье[Подробности о useRef в React] подробно объясняет это., вы можете щелкнуть ссылку, чтобы просмотреть его.
useImperativeHandle
Хук useImperativeHandle может не использоваться многими учащимися в повседневной жизни, но в некоторых случаях он поможет нам добиться некоторых неожиданных эффектов.
useImperativeHandle(ref, createHandle, [deps])
-
REF указывает на объект Ref, который необходимо назначить.
-
Возвращаемое значение функции createHandle используется как значение ref.current.
-
deps — это массив зависимостей, и функция createHandle будет повторно выполняться при изменении зависимостей.
useImperativeHandle позволяет настроить значение экземпляра, предоставляемое родительскому компоненту при использовании ref. В большинстве случаев следует избегать императивного кода, такого как ref. useImperativeHandle следует использовать сforwardRefиспользовать вместе.
Давайте рассмотрим такой пример:
import React, {
ForwardRefRenderFunction,
useImperativeHandle,
forwardRef,
useRef,
} from 'react';
interface Props {
name: string;
}
const Input: ForwardRefRenderFunction<{ focus: () => void }, Props> = (
props,
ref
) => {
const inputRef = useRef<HTMLInputElement>(null);
useImperativeHandle(
ref,
() => ({
focus: () => inputRef.current?.focus(),
}),
[]
);
return (
<div>
<input ref={inputRef}></input>
</div>
);
};
const ExportInput = forwardRef(Input);
export default ExportInput;
В приведенном выше примере мы использовали функцию useImperativeHandle для включения переданного извне объекта ref.
Мы оговариваем, что когда экземпляр компонента получен извне через ref, только один метод фокуса доступен для внешнего мира.
Это точно соответствует тому, что мы упоминали выше через useImperativeHandle. Позволяет настроить значение экземпляра, предоставляемое родительскому компоненту при использовании ref.
Конечно, такая ситуация может иметь место в повседневной разработке React.Мы хотим вызвать метод дочернего компонента в родительском компоненте, хотя React официально не рекомендует такой декларативный способ написания, но иногда нам приходится это делать.
Немного перепишем приведенный выше пример:
import React, {
ForwardRefRenderFunction,
useImperativeHandle,
forwardRef,
useRef,
} from 'react';
interface Props {
name: string;
}
export interface InputExportMethod {
focus: () => void;
domeSomeThing: () => void;
}
const Input: ForwardRefRenderFunction<InputExportMethod, Props> = (
props,
ref
) => {
const inputRef = useRef<HTMLInputElement>(null);
// 子组件方法
const domeSomeThing = () => {
// dosomething
console.log('do smething');
};
useImperativeHandle(
ref,
() => ({
focus: () => inputRef.current?.focus(),
domeSomeThing: () => domeSomeThing(),
}),
[]
);
return (
<div>
<input ref={inputRef}></input>
</div>
);
};
const ExportInput = forwardRef(Input);
export default ExportInput;
На этом этапе я могу вызвать метод, предоставляемый useImperativeHandle дочернего компонента, через ref в родительском компоненте, используя Input:
import React, { useEffect, useRef } from 'react';
import Input, { InputExportMethod } from './index';
const Parent: React.FC = () => {
const inputRef = useRef<InputExportMethod>(null);
useEffect(() => {
if (inputRef.current) {
console.log(inputRef.current.domeSomeThing());
}
}, []);
return <Input ref={inputRef} name="19Qingfeng"></Input>;
};
export default Parent;
На данный момент, когда мы открываем страницу, мы найдем, что консоль успешно распечатает:
useLayoutEffect
useLayoutEffect точно такой же, как useEffect, отличие useLayoutEffect в том, что он будет вызывать эффект синхронно после всех изменений DOM.
Вы можете использовать его для чтения макета DOM и синхронного повторного рендеринга. существуетПрежде чем браузер выполнит рисование, расписание обновления внутри useLayoutEffect будет обновляться синхронно.
Обычно для некоторых макетов, рассчитанных с помощью JS, если вы хотите уменьшить «дрожание страницы», вызванное useEffect, вы можете вместо этого использовать useLayoutEffect.
Давайте посмотрим на этот фрагмент кода:
import React, { useEffect, useRef, useState } from 'react';
function Demo() {
const ref = useRef<HTMLDivElement>(null);
const [style, setStyle] = useState<React.CSSProperties>({
position: 'absolute',
top: '200px',
background: 'blue',
});
useEffect(() => {
for (let i = 0; i < 1000; i++) {
console.log(i);
}
if (ref.current) {
const { width, height, top, left } = ref.current.getBoundingClientRect();
setStyle({
width: width + 'px',
height: height + 'px',
top: top + 'px',
left: left + 'px',
});
}
}, []);
return (
<div>
<div
ref={ref}
style={{ width: '200px', height: '200px', margin: '30px' }}
>
Hello
</div>
<div style={{ ...style, position: 'absolute' }}> This is 19Qingfeng.</div>
</div>
);
}
export default Demo;
Здесь мы используем useEffect для пересчета положения элемента div This is 19Qingfeng.после обновления страницы.
В большинстве случаев вы можете не получить никакого представления, обновив браузер, давайте попробуем снизить скорость процессора браузера и попробуем еще раз.
Здесь я уменьшил скорость процессора при производительности Chrome, давайте посмотрим на эффект в это время:
На гифке выше вы можете ясно видеть, что на странице изначально бьется синий div, и с помощью анализа производительности вы можете ясно видеть, что страница, использующая useEffect, мерцает:
Если мы заменим useEffect на useLayoutEffect, содержимое страницы useLayoutEffect будет обновляться синхронно до того, как страница будет отрисована, и заинтересованные студенты смогут проверить это в частном порядке.
Конечно, все хуки в React рассчитываются скриптами JS.Если вы когда-нибудь сталкивались с неправильным положением элемента страницы в хуке, возможно, эта статьяИспользование useEffect запускает мышление механизма выполнения браузера.поможет вам.
Конечно, есть несколько особых случаев использования useLayoutEffect:
Иногда вам может понадобиться использовать useLayoutEffect вместо useEffect в другом случае,Если вы обновляете значение (например, ref ), на этом этапе вам нужно убедиться, что оно обновлено до запуска любого другого кода.. Например:
const ref = React.useRef()
React.useEffect(() => {
ref.current = 'some value'
})
// then, later in another hook or something
React.useLayoutEffect(() => {
console.log(ref.current) // <-- this logs an old value because this runs first!
})
В этом конкретном случае использование useLayoutEffect — очень хорошее решение.
По сути, реализация useLayoutEffect основана на micro, а Effect — на macro, поэтому useLayoutEffect будет выполняться до обновления страницы.
useDebugValue
useDebugValue(value , fn)
useDebugValue можно использовать для отображения пользовательской метки хука в React DevTools, он принимает два параметра:
- value — это переменная, на которой мы хотим сосредоточиться, этот параметр представляет флаг ловушки, отображаемый в DevTools.
- fn указывает, как форматировать значение переменной, функция будет вызываться только при проверке хука. Он принимает отладочное значение в качестве аргумента и возвращает отформатированное отображаемое значение.
Когда мы настраиваем некоторые хуки, мы можем быстро найти наши собственные определенные хуки с помощью useDebugValue с помощью React DevTools.
import { useDebugValue, useState } from 'react';
function useName() {
const [state] = useState('19Qingfeng');
useDebugValue('19Qingfeng');
return state;
}
function App() {
const name = useName();
return <div>{name}</div>;
}
В этом коде я определяю метку 19Qingfeng через useDebug, теперь давайте взглянем на React DevTools:
Дополнительные предостережения:
- useDebugValue следует использовать в пользовательских хуках, оно недопустимо, если используется непосредственно внутри компонента.
- В большинстве случаев вам не нужно использовать этот хук, если только вы явно не отметите этот хук при написании какого-нибудь общего библиотечного хука.
2. Если используется useDebugValue, лучше установить второй параметр, который используется для форматирования первого параметра при каждой его проверке.
конец
Спасибо каждому другу, который смог прочитать до конца, надеюсь, содержание статьи поможет вам.
После того, как колонка Webpack закончится, я с нуля реализую эти 9 хуков в колонке React.Заинтересованные друзья могут подписаться на меня.Столбец реакции.