I have a header component that gets data using the context API in react. - It works.
However I don't like the fact that I need to provide a fall back value for the to prop in my link. Just so the page dosn't crash.
My Understanding is that this happens becuase when the page first loads "headerData" is not defind yet. When "headerData" gets the data then the page is rerendered and I get the correct value.
How can I refactor my code so that I don't need to provide a fall back value to my link component?
function Header() {
const headerData = useContext(HeaderContext);
console.log("heder data");
console.log(headerData.Menu?.PageUrl);
return (
<nav>
<Link to="/">Logo here</Link>
<ul>
<li><Link to={headerData?.Menu?.PageUrl || ""}>Menu</Link></li>
<li><Link to="/contact">Contact</Link></li>
</ul>
</nav>
)
}
From the output in the console I can see that the code runs twice.
I want to be able to change:
<li><Link to={headerData?.Menu?.PageUrl || ""}>Menu</Link></li>
to this:
<li><Link to={headerData.Menu.PageUrl}>Menu</Link></li>
CodePudding user response:
You can conditionally render something else when that data is not available
function Header() {
const headerData = useContext(HeaderContext);
console.log("heder data");
console.log(headerData.Menu?.PageUrl);
return (
<nav>
<Link to="/">Logo here</Link>
<ul>
{!!headerData?.Menu?.PageUrl
? <li><Link to={headerData?.Menu?.PageUrl!!}>Menu</Link></li>
: <></> // Or whatever you want to have when there is no header data
// e.g. <li>Menu</li>
}
<li><Link to="/contact">Contact</Link></li>
</ul>
</nav>
)
}
CodePudding user response:
To wait for the data being arrived, you can wait for it using a url state, and set the state when when the data has arrived. You don't render the link until url is being set:
function Header() {
const headerData = useContext(HeaderContext);
const [url, setUrl] = useState();
console.log("heder data");
console.log(headerData.Menu?.PageUrl);
headerData?.Menu?.PageUrl && !url && setUrl(headerData.Menu.PageUrl);
return (
<nav>
<Link to="/">Logo here</Link>
<ul>
{url?<li><Link to={url}>Menu</Link></li>:null}
<li><Link to="/contact">Contact</Link></li>
</ul>
</nav>
)
}
You could go even further and return nothing as long as url is undefined:
return (<>
{url?<nav>
<Link to="/">Logo here</Link>
<ul>
<li><Link to={url}>Menu</Link></li>
<li><Link to="/contact">Contact</Link></li>
</ul>
</nav>:null}
</>
)
}
Or use your context directly without a state:
return (<>
{headerData?.Menu?.PageUrl?<nav>
<Link to="/">Logo here</Link>
<ul>
<li><Link to={headerData.Menu.PageUrl}>Menu</Link></li>
<li><Link to="/contact">Contact</Link></li>
</ul>
</nav>:null}
</>
)
}