Автор: Дэйв Седдиа Переводчик: Front-end Xiaozhi Источник: daveceddia.
Ставь лайк и смотри, поиск в WeChat【Переезд в мир】Обратите внимание на этого человека, который не имеет большого фабричного прошлого, но имеет восходящий и позитивный настрой. эта статья
GitHub
GitHub.com/QQ449245884…Он был включен, статьи были классифицированы, и многие мои документы и учебные материалы были систематизированы.
Все говорили, что нет проекта для написания резюме, поэтому я помог вам найти проект, и это было с бонусом.【Учебник по строительству】.
Представьте себе: у вас есть функциональный компонент, который отлично работает, и однажды нам нужно добавить к нему метод жизненного цикла.
Хорошо...
Сначала мы можем задаться вопросом, как мы можем решить эту проблему, а затем, наконец, становится обычным способом преобразовать ее в класс. Но иногда мы просто используем метод функции, как его сломать?useEffect
Крюк появился, чтобы решить эту ситуацию.
использоватьuseEffect
, вы можете обрабатывать события жизненного цикла непосредственно внутри функционального компонента. Если вы знакомы с функциями жизненного цикла класса React, вы можете поместитьuseEffect
Крюк какcomponentDidMount
,componentDidUpdate
а такжеcomponentWillUnmount
Сочетание этих трех функций. Давайте посмотрим пример:
import React, { useEffect, useState } from 'react';
import ReactDOM from 'react-dom';
function LifecycleDemo() {
useEffect(() => {
// 默认情况下,每次渲染后都会调用该函数
console.log('render!');
// 如果要实现 componentWillUnmount,
// 在末尾处返回一个函数
// React 在该函数组件卸载前调用该方法
// 其命名为 cleanup 是为了表明此函数的目的,
// 但其实也可以返回一个箭头函数或者给起一个别的名字。
return function cleanup () {
console.log('unmounting...');
}
})
return "I'm a lifecycle demo";
}
function App() {
// 建立一个状态,为了方便
// 触发重新渲染的方法。
const [random, setRandom] = useState(Math.random());
// 建立一个状态来切换 LifecycleDemo 的显示和隐藏
const [mounted, setMounted] = useState(true);
// 这个函数改变 random,并触发重新渲染
// 在控制台会看到 render 被打印
const reRender = () => setRandom(Math.random());
// 该函数将卸载并重新挂载 LifecycleDemo
// 在控制台可以看到 unmounting 被打印
const toggle = () => setMounted(!mounted);
return (
<>
<button onClick={reRender}>Re-render</button>
<button onClick={toggle}>Show/Hide LifecycleDemo</button>
{mounted && <LifecycleDemo/>}
</>
);
}
ReactDOM.render(<App/>, document.querySelector('#root'));
существуетCodeSandboxпопробуй.
Нажмите "Show/Hide
"кнопка, посмотри в консоль, она печатает перед тем как исчезнуть"unmounting...
", и когда он снова появится, напечатайте "render!
".
Теперь нажмитеRe-render
кнопка. Каждый раз, когда вы нажимаете, он попадаетrender!
, который также печатаетumounting
, что кажется странным.
Почему каждый рендер печатает 'unmounting
'.
Мы можем выборочно выбрать изuseEffect
вернутьcleanup
Функция вызывается только тогда, когда компонент размонтирован. React очистится, когда компонент будет размонтирован. Как стало известно ранее,effect
Он выполняется каждый раз при рендеринге. Вот почему React реагирует на предыдущий эффект перед выполнением текущего эффекта.effect
очистить. Это на самом деле лучше, чемcomponentWillUnmount
Жизненный цикл более мощный, потому что он позволяет нам выполнять побочные эффекты до и после каждого рендеринга, если это необходимо.
неполный жизненный цикл
useEffect запускается после каждого рендеринга (по умолчанию) и может дополнительно очищаться перед повторным запуском.
скорее, чемuseEffect
Думайте об этом как о функции, которая выполняет работу трех отдельных жизненных циклов, а не просто как о способе выполнения побочных эффектов после рендеринга, включая то, что мы хотим сделать перед каждым рендерингом и перед выгрузкой, которые необходимо очистить.
Предотвратить выполнение useEffect при каждом повторном рендеринге
если хочешьeffect
Для меньшего количества запусков можно указать второй аргумент — массив значений. относиться к ним как кeffect
зависимости. Если одна из зависимостей изменилась с момента последнего раза,effect
снова побежит.
const [value, setValue] = useState('initial');
useEffect(() => {
// 仅在 value 更改时更新
console.log(value);
}, [value])
В приведенном выше примере мы передаем[value]
как второй параметр. Что делает этот параметр? еслиvalue
Значение5
и когда наш компонент повторно рендерируетvalue
По-прежнему равно 5, React будет[5]
и следующий рендеринг[5]
Сравнивать. потому что все элементы в массиве равны(5 === 5)
, React пропустит этоeffect
, что оптимизирует производительность.
Выполняется только при монтировании и размонтировании
Если вы хотите выполнить только один запускeffect
(выполняется только при монтировании и размонтировании компонента), можно передать пустой массив ([]
) в качестве второго параметра. Это говорит React, что вашeffect
Это не зависит отprops
илиstate
любое значение в , поэтому его никогда не нужно повторять. Это не особый случай — он по-прежнему следует тому, как работают зависимые массивы.
useEffect(() => {
console.log('mounted');
return () => console.log('unmounting...');
}, [])
Это будет напечатано только при первом отображении компонента.mounted
, который печатается после удаления компонента:unmounting
.
Это скрывает проблему: передача пустых массивов склонна кbug
. Если мы добавим зависимость, легко забыть добавить к ней элемент, если зависимость пропущена, значение будет использовано при следующем запуске.useEffect
время от времени не работает и может вызвать некоторые странные проблемы.
Выполняется только во время монтирования
В этом примере давайте посмотрим, как использоватьuseEffect
а такжеuseRef
крючок будетinput
Управляет фокусом на первом рендере.
import React, { useEffect, useState, useRef } from "react";
import ReactDOM from "react-dom";
function App() {
// 存储对 input 的DOM节点的引用
const inputRef = useRef();
// 将输入值存储在状态中
const [value, setValue] = useState("");
useEffect(
() => {
// 这在第一次渲染之后运行
console.log("render");
// inputRef.current.focus();
},
// effect 依赖 inputRef
[inputRef]
);
return (
<input
ref={inputRef}
value={value}
onChange={e => setValue(e.target.value)}
/>
);
}
ReactDOM.render(<App />, document.querySelector("#root"));
В верхней части мы используемuseRef
создать пустойref
. передать этоinput
изref prop
, установите его при рендеринге DOM. И, что немаловажно,useRef
Возвращаемое значение стабильно между рендерами — оно не изменится.
Поэтому, даже если мы будем[inputRef]
так какuseEffect
Второй аргумент передается, на самом деле он запускается только один раз при начальном монтировании. Это в основномcomponentDidMount
эффект.
Получить данные с помощью useEffect
Давайте рассмотрим еще один распространенный вариант использования: получение данных и их отображение. В компоненте класса мы можем поместить этот код вcomponentDidMount
метод. В хуке вы можете использовать хук useEffect для достижения, конечно, вам нужно использоватьuseState
для хранения данных.
Ниже представлен компонент, который извлекает сообщения из Reddit и отображает их.
import React, { useEffect, useState } from "react";
import ReactDOM from "react-dom";
function Reddit() {
const [posts, setPosts] = useState([]);
useEffect(async () => {
const res = await fetch(
"https://www.reddit.com/r/reactjs.json"
);
const json = await res.json();
setPosts(json.data.children.map(c => c.data));
}); // 这里没有传入第二个参数,你猜猜会发生什么?
// Render as usual
return (
<ul>
{posts.map(post => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}
ReactDOM.render(
<Reddit />,
document.querySelector("#root")
);
Обратите внимание, что мы не передали второй параметр вuseEffect
, что плохо, не делайте этого.
Непередача второго параметра приводит к запуску каждого рендеринга.useEffect
. Затем, когда он запускается, он извлекает данные и обновляет состояние. Затем, как только состояние будет обновлено, компонент будет повторно отображаться, что снова сработает.useEffect
,Вот где проблема.
Чтобы решить эту проблему, нам нужно передать массив в качестве второго параметра, что является содержимым массива.
useEffect
Единственная переменная, которая зависит отsetPosts
. Итак, мы должны передать массив здесь[setPosts]
. потому чтоsetPosts
даuseState
вернутьsetter
, поэтому он не будет воссоздаваться при каждом рендеринге, поэтомуeffect
будет работать только один раз.
Обновлять при изменении данных
Затем Virtual расширяет пример, чтобы покрыть другую распространенную проблему: как повторно получить данные, когда что-то меняется, например, идентификатор пользователя, имя и т. д.
Сначала изменимReddit
компоненты для принятияsubreddit
в качестве реквизита и на основеsubreddit
Получить данные только тогда, когдаprop
Повторить при измененииeffect
.
// 从props中解构`subreddit`:
function Reddit({ subreddit }) {
const [posts, setPosts] = useState([]);
useEffect(async () => {
const res = await fetch(
`https://www.reddit.com/r/${subreddit}.json`
);
const json = await res.json();
setPosts(json.data.children.map(c => c.data));
// 当`subreddit`改变时重新运行useEffect:
}, [subreddit, setPosts]);
return (
<ul>
{posts.map(post => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}
ReactDOM.render(
<Reddit subreddit='reactjs' />,
document.querySelector("#root")
);
Это все еще жестко закодировано, но теперь мы можем передать оболочкуReddit
компонент для его настройки, этот компонент позволяет нам изменитьsubreddit
.
function App() {
const [inputValue, setValue] = useState("reactjs");
const [subreddit, setSubreddit] = useState(inputValue);
// Update the subreddit when the user presses enter
const handleSubmit = e => {
e.preventDefault();
setSubreddit(inputValue);
};
return (
<>
<form onSubmit={handleSubmit}>
<input
value={inputValue}
onChange={e => setValue(e.target.value)}
/>
</form>
<Reddit subreddit={subreddit} />
</>
);
}
ReactDOM.render(<App />, document.querySelector("#root"));
Попробуйте этот пример в CodeSandbox.
Приложение поддерживает здесь два состояния: текущее входное значение и текущееsubreddit
. форма отправки будет отправленаsubreddit
, что приводит кReddit
Восстановить данные.
Кстати: Будьте внимательны при вводе, так как нет обработки ошибок, поэтому при вводеsubreddit
Если нет, приложение взорвется, и в качестве упражнения для вас будет реализована обработка ошибок.
Вы можете использовать только одно состояние для сохранения ввода, а затем отправить то же значение вReddit
,ноReddit
Компонент извлекает данные каждый раз, когда нажимается клавиша.
верхuseState
Выглядит немного странно, особенно вторая строчка:
const [inputValue, setValue] = useState("reactjs");
const [subreddit, setSubreddit] = useState(inputValue);
мы кладемreactjs
Начальное значение передается в первое состояние, что имеет смысл, это значение никогда не изменится.
А как насчет второй строки, что, если начальное состояние изменилось, например, когда вы вводитеbox
когда.
запомнить,useState
имеет состояние. Он использует начальное состояние только один раз, при первом рендеринге, после чего оно игнорируется. Таким образом, безопасно передавать временное значение, например, то, которое может измениться, или другие переменные.prop
.
много применений
использоватьuseEffect
Как швейцарский армейский нож. Его можно использовать для многих вещей, от настройки подписок до создания и очистки таймеров, до измененияref
ценность .
а такжеcomponentDidMount
,componentDidUpdate
Разница в том, что после того, как браузер завершит компоновку и рисунок, он передается вuseEffect
Функция будет вызываться лениво. Это делает его подходящим для многих распространенных сценариев побочных эффектов, таких как настройка подписок и обработка событий, поэтому операции, которые блокируют обновление экрана браузером, не должны выполняться в functions.
Тем не менее, не всеeffect
можно задержать. Например, видимые пользователю изменения DOM должны выполняться синхронно до того, как браузер выполнит следующую отрисовку, чтобы пользователь не заметил визуального несоответствия. (Концептуально похоже на разницу между пассивным прослушиванием событий и активным прослушиванием событий.)React
ВдобавокuseLayoutEffect
Крюк для обработки такого родаeffect
. это иuseEffect
Структура та же, разница только во времени вызова.
несмотря на то чтоuseEffect
Задержит выполнение после того, как браузер отрисует, но гарантированно выполнится до любых новых рендеров. React обновит последний рендер перед обновлением компонента.effect
.
оригинал:Дэйв измерил эффект wai.com/use — а также…
Ошибки, которые могут существовать после развертывания кода, не могут быть известны в режиме реального времени.Чтобы решить эти ошибки впоследствии, много времени тратится на отладку журнала.Кстати, я рекомендую всем полезный инструмент мониторинга ошибок.Fundebug.
общаться с
Статья постоянно обновляется каждую неделю. Вы можете выполнить поиск «Big Move to the World» в WeChat, чтобы прочитать и обновить ее как можно скорее (на одну или две статьи раньше, чем в блоге). Эта статья находится на GitHub.GitHub.com/QQ449245884…Он был включен, и многие мои документы были разобраны. Добро пожаловать в Звезду и совершенство. Вы можете обратиться в тестовый центр для ознакомления во время собеседования. Кроме того, обратите внимание на паблик-аккаунт и ответьте в фоновом режиме.Благосостояние, вы можете увидеть преимущества, вы знаете.