2
votes

I am trying to style a Navbar Link depending on the current path in my React App, if the path is /create or /add it should change it's styling. Here is what I have so far in my header component:

          <div
            id="createLink"
            className={this.state.createClassName}
            onClick={() => this.handleModalToggle()}
          >
            CREATE
          </div>

  handleActiveLink= () => {
    let path = this.props.location.pathname
     if (path === "/add" | path === "/create") {
       this.setState({createClassName: "nav-link-active"})
     } else {
       this.setState({ createClassName: "nav-link" })
     }
  };

  componentDidMount() {
    this.handleActiveLink()
  }

This works but only after I refresh the page which makes sense but it's not what I want. So I am looking for a way to change the className before even rendered and get the path first (I am using withRouter from react-router-dom)

1
react-router-dom has built in functionality to set active class to active route. Use NavLink instead. github.com/ReactTraining/react-router/blob/master/packages/…demkovych
reactrouter.com/web/api/NavLink and add some logic to set the activeClassName. Don't reinvent the wheel and add more of them.Drew Reese
I avoided using NavLink because it requires a path where to redirect. In my case I only want to open a Modal to Choose some options (creating or adding a entry) which then redirects the user to /create or /addChris
In this case I recommend not storing such transient data in state, it can be simply derived from the props and set as a className in the render function.Drew Reese

1 Answers

2
votes

Issue appears to be you only check the path when the component mounts and not when it updates. You should also check in componentDidUpdate

handleActiveLink= () => {
  let path = this.props.location.pathname;
  if (path === "/add" || path === "/create") {
    this.setState({createClassName: "nav-link-active"});
  } else {
    this.setState({ createClassName: "nav-link" });
  }
};

componentDidMount() {
  this.handleActiveLink();
}

componentDidUpdate() {
  this.handleActiveLink();
}

In this case I instead recommend not storing such transient data in state, and simply derive it from the props and set as a className in the render function (or wherever you render it). This way it's computed each render when the UI is going to be updated by something and will always be up-to-date (i.e. you won't need to worry about lifecycle functions).

render() {
  const { location: { pathname } } = this.props;
  const linkClass = ["/add", "/create"].includes(pathname)
    ? "nav-link-active"
    : "nav-link";

  ...

  <div
    id="createLink"
    className={linkClass}
    onClick={() => this.handleModalToggle()}
  >
    CREATE
  </div>
  ...
}