'rendering component, after another distant component renders

In navigation menu app, down the component tree, there is a dropdown menu component DropdownMenu2, with menu items, which are <NavLinks> components. Every time an item is clicked, it points to one of the <Route>s in main App. Every <Route> is a page, containing Infofield component. So every time <NavLink> is clicked, Infofield is rendered.

My puzzle is: I need the HeaderLogo component be rendered, everytime Infofield is rendered (HeaderLogo contains animation). I failed when constructing useEffect hook in Infofield. That hook was intended to contain custom hook, producing a variable with changing state. That hook could be then lifted up to App, from there variable would be passed to HeaderLogo, inline to the key property. If that idea is legit, I'm experiencing difficulties with construction of custom hook inside of useEffect. Maybe (probably) there is a better way...


Apps most basic structure looks like this:

App

import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import HeaderLogo from "./components/HeaderLogo";
import NaviMain from "./components/NaviMain";
import Info from "./pages/Info";
/...
import { UserContext } from "./components/sub-components/UserContext";
   
function App() {
    
  return (
    <Router>
        <div className="App">
          
            <HeaderLogo />
            <NaviMain  />

          <Routes>
             <Route path="/Info" element={<Info />} />
             /...           
          </Routes>
          
        </div>
    </Router>
  );
}

export default App;

NaviMain

import "./NaviMain.css";
import NaviMainButton from "./NaviMainButton";
import NaviMainButtonDrop2 from "./NaviMainButtonDrop";

const NaviMain = () => {

  return (

        <nav>
            <ul>
                <NaviMainButtonDrop2 />
            </ul>
      </nav>  
  )
}
export default NaviMain

NaviMainButtonDrop2

import DropdownMenu2 from "./DropdownMenu2";

const NaviMainButtonDrop2 = () => {
  
  return (
    <li>
        <a>
           title
        </a>
        <DropdownMenu2 /> 
    </li>
  )
}
export default NaviMainButtonDrop2

DropdownMenu2

import "./DropdownMenu.css"
import { NavLink } from "react-router-dom";
import { MenuItemContentSchool } from "./sub-components/MenuItemContentSchool"

const DropdownMenu2 = () => {
    
  return (
    <div className=dropdown-holder-us>
      {/* here menu unfolds */}
    {MenuItemContentSchool.map((item) => {
      return (
        <NavLink
            to={item.link} 
            className={(navData) => (navData.isActive ? "d-content-us active-style" : 'd-content-us')} 
            key={item.id} 
        >
          {item.title}
        </NavLink> 
      )
    })}
    </div>
  )
}
export default DropdownMenu2

Info (one of the <Route>'s )

import InfoField from "../components/InfoField"


const Info = () => {
  return (
    <section className="intro-index">
      <InfoField text={"welcome"} />
    </section>
  )
}
export default Info

HeaderLogo

import "./HeaderLogo.css";

const HeaderLogo = () => {

  return (
    <header>
        <h1 className="head-main">learning curve</h1>
    </header>
  )
}
export default HeaderLogo


Solution 1:[1]

From what I can gather you simply want to "rerun" an animation in the HeaderLogo component when the path changes. Import and use the useLocation hook and use the pathname value as a React key on the header element with the animation to want to run when it mounts. The idea here is that when the React key changes, React will remount that element.

Example:

import { useLocation } from "react-router-dom";
import "./HeaderLogo.css";

const HeaderLogo = () => {
  const { pathname } = useLocation();
  return (
    <header>
      <h1 key={pathname} className="head-main">
        learning curve
      </h1>
    </header>
  );
};

export default HeaderLogo;

Edit rendering-component-after-another-distant-component-renders

Solution 2:[2]

This is a classic job for a global state. You can declare a boolean state, i.e showHeader, and add conditional rendering to the tag. The global state variable showHeader will be changed each time you click on a dropdown item, and in the App functional component you should listen for a change in this variable. (For example, using Redux, you'll use useSelector(state=>state.showHeader) in App.

For an example, this is the App component with conditional rendering for the HeaderLogo. In order for this to be useable, you need to build a Redux store and reducer functions. Read the official Redux docs for more

import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import { useSelector } from 'react-redux';
import HeaderLogo from "./components/HeaderLogo";
import NaviMain from "./components/NaviMain";
import Info from "./pages/Info";
/...
import { UserContext } from "./components/sub-components/UserContext";
   
function App() {
  const showHeader = useSelector(state=>state.showHeader)
  return (
    <Router>
        <div className="App">
          
            {showHeader ? <HeaderLogo /> : null}
            <NaviMain  />

          <Routes>
             <Route path="/Info" element={<Info />} />
             /...           
          </Routes>
          
        </div>
    </Router>
  );
}

export default App;
    </Router>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Drew Reese
Solution 2 Alon Barenboim