useEffect — это ядро React Hooks, необходимо убедиться, что вы понимаете его механизм работы и правильное использование, чтобы избежать таких ям. В моей предыдущей работе из-за этого я столкнулся с бесчисленными ямами, такими как полученное значение устарело, оно не выполняется, когда оно должно выполняться, и выполняется, когда оно не должно выполняться...
Итак, чтобы избежать вышеуказанного смущения, сэкономить время на то, чтобы ломать голову в поисках ошибок, и защитить нашу линию роста волос, мы должны серьезно научиться правильно использовать хук useEffect.
что такое эффект
Как говорится, если ты знаешь врага и знаешь врага, ты будешь в опасности в сотне битв.Давайте сначала поймем, что волшебный конь - это Следствие. На самом деле, все в той или иной степени в процессе разработки сталкивались с концепцией побочных эффектов, то есть
useEffect
специально используется для записиОтношение к жизненному циклу
Статьи на рынке, включая официальные документы, позволяют намuseEffect
представлять себеcomponentDidMount
,componentDidUpdate
,componentWillUnmount
Сочетание трех жизненных циклов. Не совсем, если вам нужноuseEffect
Механизм работы зависит от жизненного цикла, что вызовет некоторую логическую путаницу, а затем вызовет ошибки. Все, что нам нужно сделать, это положитьuseEffect
Как совершенно новая функция, она посвящена функциональным компонентам, так что вы не будете путаться при ее использовании. Ниже мы демонстрируем его различные варианты использования на примерах.
Продолжительность
useEffect
Он должен выполняться один раз во время рендеринга., остальные тайминги зависят от следующих условий:
- Второго параметра нет.
useEffect
Хук принимает два параметра, первый — это код, который нужно выполнить, а второй — массив, задающий набор зависимых переменных, при изменении любой из которых эффект будет выполняться повторно. - Нет возвращаемого значения.
useEffect
Функция может быть возвращена в коде выполнения .Эта функция будет выполняться перед каждым новым рендерингом или когда компонент размонтируется для очистки.
Давайте сначала рассмотрим простой пример. Если вы хотите увидеть полный код и поиграть с ним, нажмите кнопку ниже.
Сначала посмотрим на верх<App />
код:
function App() {
const [showList, setShowList] = useState(false);
const [postCount, setPostCount] = useState(5);
return (
<div className="App">
<button onClick={() => setShowList(!showList)}>
{showList ? "隐藏" : "显示"}
</button>
<button onClick={() => setPostCount(previousCount => previousCount + 1)}>
增加数量
</button>
{showList && <PostList count={postCount} />}
</div>
);
}
Этот компонент используется для отображения списка статей, а также кнопок для управления отображением списка статей и кнопок для управления количеством отображаемых статей. мы используемshowList
государство контролировать<PostList />
отображать или нет. это сделать<PostList />
Компонент размонтируется, а затем рендерится, чтобы доказать, что каждый раз, когда он рендерится и размонтируется,useEffect
хук запустится один раз.<PostList />
Код компонента выглядит следующим образом:
function PostList({ count = 5 }) {
useEffect(() => {
let p = document.createElement("p");
p.innerHTML = `当前文章数量:${count}`;
document.body.append(p);
});
return (
<ul>
{new Array(count).fill("文章标题").map((value, index) => {
return (
<li key={index}>
{value}
{index + 1}
</li>
);
})}
</ul>
);
}
Этот компонент показывает<ul>
Список ради простоты генерирует несколько скучных заголовков статей. Давайте сосредоточимся наuseEffect
Проделанные действия:
- Создавать
p
элемент - настраивать
p
Текст - это номер текущей статьи - добавить
p
прибытьbody
последний
Здесь эффект не возвращает никакого значения и не передает ему ни одного параметра, что это будет за эффект?
Ответ заключается в том, что этот эффект будетcount
илиshowList
каждый щелчок при изменении显示
или增加数量
кнопка, наша недавно добавленнаяp
будет добавлено снова.Это также яма, которая вызывает утечку контента, если мы добавим сюда слишком много вещей, потребляющих память, без очистки, браузер не заставит себя долго ждать ~ Решение очень простое, дайтеuseEffect
Добавьте возвращаемое значение и внутри него удалите то, которое мы добавляемp
элемент может быть:
useEffect(() => {
let p = document.createElement("p");
p.innerHTML = `当前文章数量:${count}`;
document.body.append(p);
return () => {
p.remove();
};
});
Таким образом, когда мы нажимаем кнопку, мы гарантируем, что есть только одинp
на текущей странице. Видишь, не лучше ли так писать, чем раскидыватьcomponentDidMount
а такжеcomponentWillUnmount
Это удобнее? Мы можем легко получить его в том же объемеp
, просто удалите его.
Пример класса в действии — очистка данных
чтобы продолжитьuseEffect
крючок, я написал пример, основанный на ситуации, возникшей в реальной работе, здесь мы используемuseEffect
Для извлечения данных также отображается список статей блога. Чтобы просмотреть полный код, нажмите кнопку ниже, чтобы просмотреть:
В этом примере<PostList />
Код компонента был немного изменен, сначала мы определяем два новых состояния:
- сообщения. Сохранить список статей, загруженных удаленно
- загрузка. Журнал статуса запроса ajax
const [posts, setPosts] = useState([]);
const [loading, setLoading] = useState(false);
Сначала мы думалиfetch
является асинхронной операцией, то вы должны датьuseEffect
Передаёт ли хук асинхронную функцию? Неправильно, функция, переданная в useEffect, не может быть асинхронной, потому что суть асинхронности в том, чтобы вернуть промис, аuseEffect
Единственным возвращаемым значением является функция. Используя async, я получаю следующее исключение:
Warning: An effect function must not return anything besides a function, which is used for clean-up.
// 错误
useEffect(async () => {
// const response = await fetch("https://jsonplaceholder.typicode.com/posts");
});
Правильный способ его написания — определить логику захвата данных в отдельную функцию, а затемuseEffect
назовите это:
useEffect(() => {
// const response = await fetch("https://jsonplaceholder.typicode.com/posts");
const loadPosts = async () => {
setLoading(true);
const response = await fetch(
`https://jsonplaceholder.typicode.com/posts?_limit=${count}`
);
const data = await response.json();
setPosts(data);
setLoading(false);
};
loadPosts();
}, [count]);
Что он делает, перед запросом данных помещаетloading
статус установлен в true, то в соответствии сcount
значение, чтобы получить соответствующее количество списков статей, и обновить возвращаемое значение доposts
состояние, затем поставитьloading
Установите значение «ложь». Наконец, согласноloading
состояние, мы показываем加载中
или文章列表
:
if (loading) return <div>loading...</div>;
return (
<ul>
{posts.slice(0, count).map((post, index) => {
return <li key={post.id}>{post.title}</li>;
})}
</ul>
);
второй параметр
В приведенном выше примере мы даемuseEffect
передал второй параметр и поставилcount
как зависимое значение всякий раз, когдаcount
При изменении этот эффект будет повторно выполнен один раз для загрузки новых данных. Кроме того, если мы скроем список и нажмем显示
При нажатии кнопки эффект также будет запущен снова, потому что, когда щелчок скрыт,<PostList />
Компонент размонтируется, а затем перерисовывается, когда он снова отображается, мы можем в соответствии сloading...
Этот знак можно увидеть.
если мыЕсли вы удалите второй параметр, вы попадете в яму бесконечного цикла.,Зачем? Потому что при выполнении эффекта он будет обновлятьсяposts
а такжеloading
Эти два состояния, и когда состояние изменится, компонент снова будет повторно отображаться в соответствии сuseEffect
Нетрудно сделать выводы из закона, что каждый рендер должен быть выполнен один раз.
то если мыКак насчет того, чтобы дать ему пустой массив? Тогда как бы вы не нажимали на увеличение числа, этот эффект не будет выполнен повторно, в результате чего всегда загружаются только 5 статей по умолчанию.
Добавить другие свойства
Мы можем попробовать добавить еще одно свойство для проверкиuseEffect
Зависит от свойств массива. существует<App />
В компонент добавляем состояние макетаvertical
и кнопки для изменения макета для управления<PostList>
Горизонтальное и вертикальное расположение компонентов:
// APP
function App() {
// 其它代码省略
const [vertical, setVertical] = useState(true);
return (
<div className="App">
{/* 其它代码省略 */}
<button onClick={() => setVertical(prev => !prev)}>更改布局</button>
{showList && <PostList count={postCount} vertical={vertical} />}
</div>
);
}
// PostList
function PostList({ count = 5, vertical = false }) {
// 其它代码省略
useEffect(() => {
// const response = await fetch("https://jsonplaceholder.typicode.com/posts");
const loadPosts = async () => {
setLoading(true);
const response = await fetch(
`https://jsonplaceholder.typicode.com/posts?_limit=${count}`
);
const data = await response.json();
setPosts(data);
setLoading(false);
};
loadPosts();
}, [count, vertical]); // 在这里添加 vertical 作为依赖
// 其它代码省略
}
Здесь мы добавляем второй параметрvertical
зависимы, так что каждый щелчок更改布局
При нажатии кнопки список статей будет загружен один раз, что подходит для ситуации, когда данные нужно повторно запрашивать при изменении макета:
Если вам не нужно перезагружать данные, просто поставьтеvertical
Просто удалите его из массива зависимостей.
фокус
Посмотрите на часто используемыеuseEffect
Правильно ли используется? Чтобы отметить ключевые моменты:
- это не совсем
componentDidMount
,componentDidUpdate
,componentWillUnmount
Сочетание трех жизненных циклов (у людей свои представления). - Он будет выполняться один раз при каждом рендеринге.
- Если возвращается функция, код, который возвращает функцию, должен быть запущен один раз до следующего рендеринга или до размонтирования компонента.
- Если зависимый массив указан и не пуст, он будет перезапущен при изменении каждого элемента в массиве.
- Если массив пуст, он будет выполнен только один раз при первом рендеринге, если есть возвращаемое значение, такое же, как 3.
- если в
useEffect
Если состояние обновляется в , а массив зависимостей не указан или состояние существует в массиве зависимостей, это вызовет бесконечный цикл.
Вы все поняли? Если у вас есть какие-либо вопросы, пишите мне в комментарии или в личные сообщения! Если вы считаете, что статья полезна, пожалуйста, подпишитесь на блогера, спасибо, сравните свое сердце.