Sam
Sam

Reputation: 2341

React: Update variable when url changes with useEffect, react-router

I'm trying to create a navbar where the link of the current page is highlighted. You can see a live example of my attempt here. The correct page is highlighted if you refresh the page, but not from just clicking on a link. I've tried to set my useEffect params as [window] [window.location] and [window.location.href] and nothing works.

const PageLinks = ({ links, className = "" }) => {
  
  const [urlPath, setUrlPath] = useState("");

  useEffect(() => {
    setUrlPath(url.parse(window.location.href).pathname);
  }, [window]);

  return (
    <>
      {Object.keys(links).map((key) => {
        
        const active = (
          urlPath == `/${key}` || 
          urlPath == "/" && key == "home"
        );

        return (
          <Link
            to={links[key]}
            key={key}
          >
            {key}
          </Link>
        )
      })}
    </>
  );
};

Github Repo of the whole project

https://github.com/samgermain/react-boiler-plate

Upvotes: 0

Views: 760

Answers (1)

tgikf
tgikf

Reputation: 557

There's no need to track the entire window object. You can store the currently selected menu item in a state and then conditionally format menu items, if the specific element equals the one in the state (see code snippet).

To apply the conditional formatting when the user directly navigates to the url instead of clicking one of the items (e.g. changing /home to /about), you can use the useLocation hook.

const { useState } = React;

const NavItem = (props) => {
  return (
    <li><a href="#">
      {props.current ? (
        <strong>{props.label}</strong>
      ) : (
        <span onClick={props.setSelected}>{props.label}</span>
      )}
    </a></li>
  );
};
const App = () => {
  const [currentItem, setCurrentItem] = useState();
  const items = ["home", "about", "contact"];
  
  return (
    <ul>
      {items.map((e) => {
        return (
          <NavItem
            label={e}
            setSelected={() => setCurrentItem(e)}
            current={currentItem === e}
          />
        );
      })}
    </ul>
  );
};

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Upvotes: 2

Related Questions