Я пытаюсь обновить некоторые компоненты в Gatsby.js в зависимости от того, по какому URL-адресу я нахожусь.
Я использую useEffect(), чтобы компоненты обновлялись только при изменении location.pathname (часть URL-адреса после домена).
Вот код:https://codesandbox.io/s/gatsbystarterdefault-290qv
По какой-то причине useEffect не использует обновленные значения реквизита location (который передается компоненту header, который, в свою очередь, оборачивает каждую страницу).
Чтобы воспроизвести, перейдите к КодПесочница выше и:
isHome when re-rendering Header — это true, а isHome at NavItemLink — это falseЛюбая идея, почему useEffect не получает последнее значение location?
Я думаю, что @AllitterativeAlice дал хороший ответ на ваш вопрос. Я также разветвил вашу песочницу и предоставил альтернативный подход к рендерингу ваших навигационных ссылок, который использует состояние для определения набора навигационных ссылок для рендеринга: codeandbox.io/s/gatsbystarterdefault-v2p5w
Спасибо, @RobertCooper. Пара комментариев: 1) Другие страницы не видят ссылки в шапке из-за дополнительного isHome if-оператора, который вы разместили в renderNavLinks. 2) Хммм, код renderNavLinks каким-то образом пропал из кодов и ящика, который вы сделали, так что теперь я не могу вспомнить свой второй комментарий..
@ Магнус, упс, я вернул код renderNavLinks. Теперь все должно работать корректно. isHome тройка просто отображает <a> элементы, если вы дома, а затем <Link> элементы, если вы не дома (та же логика, что и реализованная вами).



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Как указано в Документация 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.
@ eramit2010 Он указал, что хочет воссоздавать компоненты NavItemLink только при изменении location.pathname, а не каждый раз, когда отображается компонент заголовка.
Спасибо. Это типичный шаблон, который useEffect изменяет state компонента, чтобы принудительно выполнить повторный рендеринг? Что касается обсуждения выше, я не уверен, что полностью следую ему, но да, смысл useEffect заключался в том, чтобы navlinks обновлялись Только при изменении location.pathname (не при каждом повторном рендеринге, что происходит слишком часто).
@AllitterativeAlice, в этом случае он может использовать useMemo. сохранение в состоянии увеличит один цикл рендеринга.
Я бы рекомендовал использовать 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?
внешний заголовок, так как теперь он не зависит ни от одного из ваших реквизитов. нужен только путь, который мы передаем в качестве аргумента.
Работает отлично. Есть ли у вас какие-либо советы / ресурсы о том, как узнать, когда использовать useEffect против useMemo?
Это действительно хорошая запись в блоге Дэна о том, как написать отказоустойчивый компонент: overreacted.io/writing-resilient-components.
Я думаю, это связано с рендерингом JSX в вашем
useEffect. Не уверен, что это правильный подход к этому.