Search code examples
reactjsnext.jshrefreact-propstemplate-literals

How to prop-drill varying hrefs for various Link-components down to the original Link component?


[Solution]

Working solution suggested by @Nikhil bhatia goes as follows.
Check original post further down below for alternative idea.

export default function TopNav(props) {
    const { data } = props

    return (
      <StyledDiv>
        <nav>
          <ul>
            {data.map(item => <StyledLi key={item.name} >
              <Link href={item.href}>{item.name}</Link>
            </StyledLi> )}
          </ul>
        </nav>
      </StyledDiv>
    );
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>



Original Post

Problem

I have one component that's supposed to be the scheme for how I want to display a list of links. These links differ depending on which site I am currently on.

On the main page I can choose from about, projects, blog. Depending on which I click on, I want the respective site to show 2 links to the other 2 pages.

enter image description here

Hence... the linkname + href props change for each of the 3 pages.
So far I am passing the linkname through to the link-component, but how do I pass the href?

Question

How do I drill the individual href down to the original Link-Component?

My solution so far

Link-Component
I have tried template literals like this:

<Link href=`/{linkA_Url}`>{linkA}</Link>

export default function TopNav({ linkA, linkB }) {
  return (
    <StyledDiv>
      <nav>
        <ul>
          <StyledLi>
            <Link href="/">{linkA}</Link>
          </StyledLi>
          <StyledLi>
            <Link href="/">{linkB}</Link>
          </StyledLi>
          <StyledLi>
            <Link href="/">⬅</Link>
          </StyledLi>
        </ul>
      </nav>
    </StyledDiv>
  );a
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

Individual Component
The pages about, projects, blog use the TopNav Component shown above. Here's the about-page as example. I'm passing through the name of the link, but how I also pass the href?
It should be something like
<TopNav href="/projects" href="/blog" linkA="projects" linkB="blog" /> The href props obviously need different names, so that's where the problem starts.

export default function About({ title, linkA, linkB }) {

  return (
    <>
      <TopNav linkA="projects" linkB="blog" />
    </>
  );
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

Link to Codesandbox

If the main page doesn't show the 3 links about, projects & blog centered in the middle, reload the preview window. This is another issue that I haven't managed to resolve either. I've created a separate question for that.


Solution

  • you can refractor TopNav like this

    export default function TopNav(props) {
        const { data } = props
    
        return (
          <StyledDiv>
            <nav>
              <ul>
                {data.map(item => <StyledLi key={item.name} >
                  <Link href={item.href}>{item.name}</Link>
                </StyledLi> )}
              </ul>
            </nav>
          </StyledDiv>
        );
    }

    now you can use it like <TopNav data={[{href: "/abc", name: "ABC"}, {href: "/xyz", name: "XYZ"}]} />

    you can either use it on every page with different props,

    or

    you can use it on top level _app.jsx and give conditional data props to TopNav, you can get pathname from useRouter and depending upon the path name change data prop

    example

    const App = () => {
     const { asPath } = useRouter()
     const getData = () => {
       if (asPath === "/url1") {
         return [{href: "/abc", name: "ABC" }]
       }
       if (asPath === "/url2") {
         return [{href: "/xyz", name: "XYZ" }]
       }
       return [{href: "/wsad", name: "WSAD" }]
     }
      return(
       <>
        <TapNav data={getData()} />    
        {otherComp}
       </>
      )
    }