DEV Community

Kevin Sassé
Kevin Sassé

Posted on

Using a nested NavLink to conditionally render JSX

I've been learning React.js for the past three weeks at Flatiron School and have spent this entire week working on my end-of-phase project. One of the core requirements for the project is that it uses React Router.

Our single-page application displays a list of all the currently active NFL quarterbacks, as of 10/24/2022. The user can click on the player cards show/hide a player's stats as well as edit the stats and add players to a favorite list. We also included the ability to sort by different stats and a search feature.

One of the issues we encountered was how to only show the Search and Sort features on specific endpoints. Initially we tried to set state equal to the endpoint of the link that was clicked and use a ternary to determine which JSX elements should be returned.

return (
        <>
            <nav className="link-container">
                <NavLink className="linkButtons" to="/" onClick={handleLinkClick}>Home</NavLink>
                <NavLink className="linkButtons" to="/form" onClick={handleLinkClick}>New Player Form</NavLink>
                <NavLink className="linkButtons" to="/favorites" onClick={handleLinkClick}>Favorites List</NavLink>
                <NavLink className="linkButtons" to="/activelist" onClick={handleLinkClick}>Active List</NavLink>
            </nav>
            {pathName === "/form" || pathName === "/player/:id/EditForm" ? 
            null
            :
            <div className="search-sort">
                <Search changeSearch ={changeSearch}                              
                changeSearchValue = {changeSearchValue}
                searchValue = {searchValue} />
                <Sort changeSortBy = {changeSortBy}/>
            </div>
            }
        </>
    )
}
Enter fullscreen mode Exit fullscreen mode

This had limited success and worked on the form to add a new player but not the one to edit a player.

Image description

The console showed the correct path names for most of the endpoints. If state was being updated correctly, the final "/" should have been "/player/:id/EditForm". The link is still routing to the edit player form but appears as the home endpoint in state. We believe the cause of this issue was that the link to the edit form is nested within the player card component itself instead of the Header component like the new player form.

We tried a few different ways to try and force the correct endpoint into state by passing callback functions through the various components, and did successfully get state to display the correct endpoint. Unfortunately this had issues with the ternary as the ":id" value wasn't getting passed into the Header component. This was overly complex and would only get more involved to get the ternary working properly.

Sometimes you need to take a step back, and rethink your approach to a problem. We were able to solve this issue by using the onClick event to set state to either "true" or "false" based on the name of the <NavLink>.

const handleLinkClick =(e) => {
    e.preventDefault()
    const { name, pathname } = e.target
    if(name === "home" || name === "Favorite Players" || name === "Active Players") {
        setDisplayStatus(true)
    } else {
        setDisplayStatus(false)
    }
    changePageUrl(pathname)        
}

Enter fullscreen mode Exit fullscreen mode

We also had to pass the handleLinkClick function as a prop to the player card component to make it available to the edit form link on each card. We then were able to refactor our ternary to render the Search and Sort elements based on the state value.

    return (
        <>
            <nav className="link-container">
                <NavLink className="linkButtons" name="home" to="/" onClick={handleLinkClick}>Home</NavLink>
                <NavLink className="linkButtons" name="New Player Form" to="/form" onClick={handleLinkClick}>New Player Form</NavLink>
                <NavLink className="linkButtons" name="Favorite Players" to="/favorites" onClick={handleLinkClick}>Favorite Players</NavLink>
                <NavLink className="linkButtons" name="Active Players" to="/activelist" onClick={handleLinkClick}>Active Players</NavLink>
            </nav>
            {displayStatus === false  ? 
            null
            :
            <div className="search-sort">
                <Search changeSearch ={changeSearch}
                changeSearchValue = {changeSearchValue}
                searchValue = {searchValue} />
                <Sort changeSortBy = {changeSortBy}/>
            </div>
            }
        </>
    )
}
Enter fullscreen mode Exit fullscreen mode

If one of the falsey endpoints is clicked, the <Search/> and <Sort/> components will not be displayed. This approach is much simpler than trying to conditionally render components using a nested endpoint.

Github link for our project

Top comments (0)