Fred Barros
Fred Barros

Reputation: 31

NavLink returns active to all links and no solution in SO seems to work

It seems none of the solutions presented elsewhere works, so I decided to ask. No matter what I do, I can't get the NavLinks to be rendered differently if they are active or not. I took the ternary operator straight from the part about NavLinks in react-router-dom's documentation and I'd try to create a function to avoid having all this code written three times, but before that I'd like to at least have the correct rendering working.

(side question: why does it break if I remove the Router tags from the return statement? They're there because, before I needed the NavLinks for different styling, I was using regular routes, but if I take them out it breaks with a message about useHref, something like that)

Here's my return statement and the styled-components below it:

return (
        <>
            <GlobalStyles />
            <Router>
                <Header />
                <Wrapper>
                    <NavBar>
                        <NavLink
                            to="/search"
                            exact
                            className={(isActive) =>
                                "nav-link" + (!isActive ? " inactive" : "")
                            }>
                            Search song
                        </NavLink>
                        <NavLink
                            to="/weekly-thread"
                            exact
                            className={(isActive) =>
                                "nav-link" + (!isActive ? " inactive" : "")
                            }>
                            Weekly thread
                        </NavLink>
                        <NavLink
                            to="/game"
                            exact
                            className={(isActive) =>
                                "nav-link" + (!isActive ? " inactive" : "")
                            }>
                            Game
                        </NavLink>
                    </NavBar>
                </Wrapper>
            </Router>
        </>
    );
};

const Wrapper = styled.div`
    width: 100vw;
    height: 100vh;
    position: absolute;
    z-index: -1;
`;
const NavBar = styled.div`
    display: flex;
    padding: 20px 20px;
    position: relative;
    gap: 20px;
    font-size: 18px;
    a {
        text-decoration: none;
    }
    .nav-link {
        color: blue;
        &:inactive {
            color: black;
        }
    }
`;

EDIT: it's getting weirder. After even simply pasting the code from the answer below and not getting any results, I tried to mess with the font size for the active NavLink. To my surprise, now something changed, but in totally bizarre way, as it made the first element stay as it were before and second and third got transformed just in terms of font size, but nothing else. When I click on the other NavLinks, the URL changes, but they remain the same: the first in the original size, the other two altered.

SECOND EDIT: Trying to debug this a little further, I've done this to one of my NavLinks and the result is very weird:

<NavLink to="/search" exact className={(isActive) => {
    console.log(isActive);
    isActive === false ? console.log(isActive) : console.log("foo");
}}>Search song</NavLink>

Now, the first console.log returns the actual value of isActive, but the second and third console.logs always return, "foo", which is the second value in the ternary operator, even if I change "isActive === false" to "isActive === true", which should swap them. I have no idea what is going on here.

Upvotes: 0

Views: 1976

Answers (3)

LIannotti
LIannotti

Reputation: 382

You should be able to remove your className property from NavLink.

Remove:

className={(isActive) =>
    "nav-link" + (!isActive ? " inactive" : "")
}>

It's unnecessary as React-Router already adds the .active class to the active link, so what you're doing with that property is no doubt creating the weirdness.

You can just style the a.active however you want.

Upvotes: 0

Fred Barros
Fred Barros

Reputation: 31

After console.logs here, there and everywhere, something struck my attention: isActive appears as an object on the console. That's why I was always getting the same result.

When I changed the condition on the ternary operator to isActive.isActive ? I started getting the expected results.

Upvotes: 2

Lars
Lars

Reputation: 3573

Router

You might want to read up on the docs.
The primary components page explains why you would need a router.
It provides information for the other components; IE what the current route is.

NavLink

NavLink should be able to set their active class themselves, based on if the router is matching on the to props of the NavLink

see this CodePen for an example.

Note that you would still need need to provide the CSS for the class that is applied. If you're using a framework like bootstrap, or material-ui; they would usually have a .active css styling already in there by default.

CSS

The css rule might be incorrect, there seems to be a colon at &:inactive which probable should be .inactive class:

.nav-link {
    color: blue;
    &.inactive {
      color: black;
    }
  }

codepen

Upvotes: 0

Related Questions