DEV Community

Cover image for Building Dynamic Breadcrumbs in NextJS

Building Dynamic Breadcrumbs in NextJS

Daniel Starner on January 05, 2022

Breadcrumbs are a website navigation tool that allows users to see their current page's "stack" of how it is nested under any parent pages. Users c...
Collapse
 
theunreal profile image
Eliran Elnasi

Nice one! But not sure what asPathParts - there is no definition of it and it's being used.

Collapse
 
dan_starner profile image
Daniel Starner

Oops! You are correct. That was an artifact of my copying from my “real” code and trying to refactor the names to be more tutorial friendly. I believe I fixed it.

Collapse
 
isaactait profile image
Isaac Tait

I am getting an error re: async:

Effect callbacks are synchronous to prevent race conditions. Put the async function inside:
useEffect(() => {
  async function fetchData() {
    // You can await here
    const response = await MyAPI.getData(someId);
    // ...
  }
  fetchData();
}, [someId]); // Or [] if effect doesn't need props or state

Learn more about data fetching with Hooks: https://reactjs.org/link/hooks-data-fetchingeslintreact-hooks/exhaustive-deps
Enter fullscreen mode Exit fullscreen mode

I followed the eslint guidance to fix and now it says that useEffect is not defined. Per chance do you have the full code I could take a look at to see what I am doing wrong? Thanks for writing this btw. Great stuff. Cheers!

Collapse
 
florentinog9 profile image
FlorentinoG9

I fix it by doing this instead

inside the Crumb Component before the if( last) ....

    const router = useRouter()
    const [text, setText] = useState(defaultText)

    useEffect(() => {
        if ( !Boolean(textGenerator) ) return setText(defaultText)

        async function fetchData() {
            const currText = await textGenerator()
            setText(currText)
        }

        fetchData()

    }, [defaultText, textGenerator])
Enter fullscreen mode Exit fullscreen mode
Collapse
 
stackusman profile image
stack-usman


useEffect(() => {
let splited = router.asPath.split('/')
let bread = document.getElementById("#p");
for(let i = 1; i < splited.length; i++){
bread.innerText += i > 1 ? '/' : ''
bread.innerText += splited[i]
}
document.body.appendChild(bread)
},[router])

Nice solution you provide.
but can you suggest improvement for this.

Collapse
 
sdoxsee profile image
Stephen Doxsee

This helped. I didn't need text generators, useEffect, etc. because I just pass in the param and query to the breadcrumbitem and conditionally pull dynamic data based on the param name (e.g. [post_id]) and its value from the query. This post really helped get me going. Thanks!

Collapse
 
jcodin profile image
jCodin

Hey! Nice tutorial, thank you for that, great work!

I wonder how the breadcrumb component gets notified about the changing route, because it seems like you don´t even have to listen to some events or similiar.

Could you tell me how the breadcrumb component knows when to update itself? (and which part of your provided code is responsible for that?)

Kind regards,
Jendrik

Collapse
 
florentinog9 profile image
FlorentinoG9

it updates it self with the useMemo's dependencies array [router.asPath, router.pathname, router.query, getTextGenerator, getDefaultTextGenerator]

I think you could take off the router.query from the dependencies since the router.query is an object and will not know if the values of that object are changing but will have to try that

Collapse
 
hendisantika profile image
Hendi Santika

Nice article.

Is there any github repo to clone?

Thanks

Collapse
 
sunflowertc profile image
sunflower-tc

Hi, can you provide me with the git address of the code? Thank you very much!

Collapse
 
janoschherrmann profile image
Janosch Herrmann

Hey @dan_starner, it seems like this wouldn't work with catchall routes in Next, as creating the crumblist throws an error.

Collapse
 
copernico profile image
Steve

This code is not working for me... it shows all kind of errors.