Реакция: не гарантируется ли использование useEffect до рендеринга компонента?

Я пытаюсь обновить некоторые компоненты в Gatsby.js в зависимости от того, по какому URL-адресу я нахожусь.

Я использую useEffect(), чтобы компоненты обновлялись только при изменении location.pathname (часть URL-адреса после домена).

Вот код:https://codesandbox.io/s/gatsbystarterdefault-290qv

По какой-то причине useEffect не использует обновленные значения реквизита location (который передается компоненту header, который, в свою очередь, оборачивает каждую страницу).

Чтобы воспроизвести, перейдите к КодПесочница выше и:

  1. Нажмите на страницу 2, затем вернитесь на страницу 1.
  2. См. операторы консоли, что isHome when re-rendering Header — это true, а isHome at NavItemLink — это false

Любая идея, почему useEffect не получает последнее значение location?

Я думаю, это связано с рендерингом JSX в вашем useEffect. Не уверен, что это правильный подход к этому.

Robert Cooper 26.05.2019 18:30
Как указано в документах, useEffect запускает рендер после, не раньше.
Joe Clay 26.05.2019 18:31

Я думаю, что @AllitterativeAlice дал хороший ответ на ваш вопрос. Я также разветвил вашу песочницу и предоставил альтернативный подход к рендерингу ваших навигационных ссылок, который использует состояние для определения набора навигационных ссылок для рендеринга: codeandbox.io/s/gatsbystarterdefault-v2p5w

Robert Cooper 26.05.2019 18:46

Спасибо, @RobertCooper. Пара комментариев: 1) Другие страницы не видят ссылки в шапке из-за дополнительного isHome if-оператора, который вы разместили в renderNavLinks. 2) Хммм, код renderNavLinks каким-то образом пропал из кодов и ящика, который вы сделали, так что теперь я не могу вспомнить свой второй комментарий..

Magnus 26.05.2019 19:02

@ Магнус, упс, я вернул код renderNavLinks. Теперь все должно работать корректно. isHome тройка просто отображает <a> элементы, если вы дома, а затем <Link> элементы, если вы не дома (та же логика, что и реализованная вами).

Robert Cooper 26.05.2019 19:05
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
3
5
514
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Как указано в Документация React по useEffect, useEffect «похож на componentDidMount и componentDidUpdate». Это означает, что да, он запускается только после рендеринга компонента.

Вам нужно перерендерить компонент заголовка после изменения navLinks. Я рекомендую сделать это, сделав navLinks частью состояния компонента с помощью хука useState:

const [navLinks, setNavLinks] = useState([])

useEffect(() => {
    setNavLinks(
        nav.map((navItem, index) => (
            <NavItemLink
              key = {navItem.name}
              name = {navItem.name}
              to = {navItem.path}
              isHome = {location.pathname === withPrefix("/")}
            />
        ))
    )
}, [location.pathname])

Я создал форк вашей песочницы кода с обновленным компонентом заголовка для использования хука useState, как показано выше: https://codesandbox.io/s/gatsbystarterdefault-ftogs

почему ему нужно поставить компонент в состояние. я думаю, что реакция позаботится об обновлении реквизита, если он просто вставит возвращенный jsx.

Amit Chauhan 26.05.2019 18:42

@ eramit2010 Он указал, что хочет воссоздавать компоненты NavItemLink только при изменении location.pathname, а не каждый раз, когда отображается компонент заголовка.

AlliterativeAlice 26.05.2019 18:45

Спасибо. Это типичный шаблон, который useEffect изменяет state компонента, чтобы принудительно выполнить повторный рендеринг? Что касается обсуждения выше, я не уверен, что полностью следую ему, но да, смысл useEffect заключался в том, чтобы navlinks обновлялись Только при изменении location.pathname (не при каждом повторном рендеринге, что происходит слишком часто).

Magnus 26.05.2019 18:47

@AllitterativeAlice, в этом случае он может использовать useMemo. сохранение в состоянии увеличит один цикл рендеринга.

Amit Chauhan 26.05.2019 18:56
Ответ принят как подходящий

Я бы рекомендовал использовать useMemo вместо useEffect или хранить его внутри состояния. useMemo будет вычислять навигационные ссылки только тогда, когда изменится их зависимость.

const generateNavLinks = path => nav.map((navItem, index) => (
  <NavItemLink
    key = {navItem.name}
    name = {navItem.name}
    to = {navItem.path}
    isHome = {path === withPrefix("/")}
  />
));

const navLinks = useMemo(() => generateNavLinks(location.pathname), [location.pathname]);

Спасибо. Вы бы поместили geneateNavLinksза пределами функцию компонента Header, а функцию navLinksв пределах — функцию компонента Header?

Magnus 26.05.2019 18:57

внешний заголовок, так как теперь он не зависит ни от одного из ваших реквизитов. нужен только путь, который мы передаем в качестве аргумента.

Amit Chauhan 26.05.2019 18:59

Работает отлично. Есть ли у вас какие-либо советы / ресурсы о том, как узнать, когда использовать useEffect против useMemo?

Magnus 26.05.2019 19:23

Это действительно хорошая запись в блоге Дэна о том, как написать отказоустойчивый компонент: overreacted.io/writing-resilient-components.

Amit Chauhan 27.05.2019 09:51

Другие вопросы по теме