Как определить, присутствует ли в документе другой компонент? - PullRequest
0 голосов
/ 31 января 2020

У меня есть сайт, построенный с React Stati c, в котором всегда присутствует компонент Header. В зависимости от того, имеет ли текущая страница компонент героя или нет, заголовок должен быть либо светлым, либо темным.

Заголовок отображается вне маршрутов, и useEffect запускается до отображения дочерних элементов. Это , вероятно из-за маршрутизации.

Это текущий код:

// App.js
import React, { useState, useEffect } from 'react'
import { Root, Routes } from 'react-static'

export default () => {

    const [useDarkTheme, setUseDarkTheme] = useState(false);

    useEffect(() => {
        if (typeof document !== "undefined") {
            const heroPresent = document.querySelectorAll(".o-hero").length > 0;
            console.log("The hero is present: " + heroPresent);
            setUseDarkTheme(!heroPresent);
        }
    })

    return (
        <Root>
            <React.Suspense fallback={ <em>Loading...</em> }>
                <Header useDarkTheme={ useDarkTheme } />
                <Routes default />
            </React.Suspense>
        </Root>
    );
}

То, что будет отображаться на <Routes default />, - это состояние c страниц. настроен в React Stati c static.config.js.

Ниже приведен пример компонента Hero:

// Hero.js
import React from "react";

export default () => {
    console.log("This is the Hero rendering. If this exist, the Header should be dark.");

    return (
        <div className="o-hero">
            <p>Hero!</p>
        </div>
    );
}

Когда я запускаю приложение и смотрю журналы, вот что я получаю:

The hero is present: false
This is the Hero rendering. If this exist, the Header should be dark.

Как Могу ли я как-то обнаружить присутствие Героя из Заголовка, хотя Герой находится в маршрутизаторе, а Заголовок - нет? Это похоже на довольно распространенный вариант использования, но я не смог найти никакой информации о паутинах.

Заранее спасибо!

1 Ответ

0 голосов
/ 03 февраля 2020

Итак, я использовал useContext, чтобы предоставить всем детям метод получения и установки темы заголовка (темный или светлый). Решение очень вдохновлено этим ответом . Решение выглядит следующим образом:

// App.js
import React, { useState, useContext } from 'react'
import { Root, Routes } from 'react-static'
import { HeaderThemeContext } from "./context";

export default () => {

    const { theme } = useContext(HeaderThemeContext);
    const [headerTheme, setHeaderTheme] = useState(theme);

    return (
        <Root>
            <React.Suspense fallback={ <em>Loading...</em> }>
                <HeaderThemeContext.Provider value={ { theme: headerTheme, setTheme: setHeaderTheme } }>
                    <Header theme={ headerTheme } />
                    <Routes default />
                </HeaderThemeContext.Provider>
            </React.Suspense>
        </Root>
    );
}
// Hero.js
import React from "react";
import { headerThemes, setHeaderTheme } from "./context";

export default () => {
    setHeaderTheme(headerThemes.DARK); 

    console.log("This is the Hero rendering. If this exist, the Header should be dark.");

    return (
        <div className="o-hero">
            <p>Hero!</p>
        </div>
    );
}
// context.js
import React, { createContext, useContext } from "react";

export const headerThemes = {
    LIGHT: "light",
    DARK: "dark",
};

export const HeaderThemeContext = createContext({
    theme: headerThemes.LIGHT,
    setTheme: () => {}
});

// This is a hook and can only be used in a functional component with access to the HeaderThemeContext.
export const setHeaderTheme = theme => useContext(HeaderThemeContext).setTheme(theme);

Это дает глобальный доступ для установки и получения темы заголовка, что может быть необязательным, но пока работает, и я думаю, что все в порядке. Пожалуйста, дайте мне знать, если есть лучший способ сделать это.

...