emgoto / emgoto-comments

This hosts the comments for my blog, emgoto.com.
https://emgoto.com
0 stars 0 forks source link

react-table-of-contents/ #4

Open utterances-bot opened 3 years ago

utterances-bot commented 3 years ago

How to build a table of contents in React · Emma Goto

A table of contents lets your readers see a high-level summary of your page. In this tutorial, we’ll be building a table of contents with…

https://www.emgoto.com/react-table-of-contents/?utterances=cb76f71c5ea279361ddcade8G3VsDF9LGEbM9j7t0NjJrRRwMi%2Fwt2n7Qy5BbbfDKoKpDt07SCL6DeQ%2F0NznvBhqftZ%2FWJ2FNRSTdyAAZ83F%2FAPuvbzb0AoybDIvucCuU5M2QmBnOIdsNfOpNgw%3D

gabrielcsapo commented 3 years ago

This was super helpful! Exactly what I needed for my gatsby site!

maxeth commented 3 years ago

Insanely helpful, thank you :)

awu12442 commented 3 years ago

thank you!!!!!!

daveteu commented 3 years ago

Everything clearly covered for markdown toc. Excellent tutorial!

Thank you!

acmoles commented 3 years ago

This guide is excellent.

In my Gatsby site I needed to clean up the effect on each location change and empty the headerElementsRef.

 React.useEffect(() => {
  ...
  return () => {
     observer.disconnect();
     headingElementsRef.current = {};
  };
}, [location]);
wildky commented 3 years ago

Thanks! I loved this walk through - very thorough and a great implementation.

One thing about this implementation makes for a sort of buggy UX experience. When a user scrolls up from one section in the table of contents to the one above it, the section highlighted in the Table of Contents does not update. This is because the activeId is not updated until the observer gets the header of a section (which can be a while if you are scrolling up through a large section).

I modified your code by tracking the entire container of each section (with all the body text too) so that the highlighted element in the Table of Contents is always accurate, not just when scrolling down!

Cheers, Ky

Ginxo commented 2 years ago

Such a great post Thanks a lot!!! For anyone how is interested I have adapted this to react + redux + antd menu component https://github.com/Ginxo/chain-status/blob/a38419858f565376de731234a3d7a9ffadbba59c/packages/webpage/src/components/current-status/CurrentStatusMenu.tsx#L78

Cheers, Kike.

Nephter commented 2 years ago

Easily the best ToC walkthrough. Problem: When I click a link all my links flash. My ToC is rendered in a layout component and hydrated by [slug] data. I'm using Next js Im new to coding so if you need more info let me know. Also I can link my repository if need be. Thanks so much for this. I was having a miserable time trying to use other's ToCs

emgoto commented 2 years ago

Hi @Nephter! If you don't mind a slow turnaround (not sure when I can take a look) you can either DM me on Twitter or drop the link to the repository here :)

Nephter commented 2 years ago

Hey @emgoto. Thanks for the reply. I figured it out. I was relying to much on state change and it was causing re renders to my page.

ashish-chide commented 2 years ago

Hey, can someone please explain the reason why do we maintain a map(headingElementsRef) inside a ref? @emgoto

yaayes commented 1 year ago

Thank you Emma for the detailed post about table of content, I've just started playing with Gatsby and your post helped me a lot!

rocamocha commented 1 year ago

Hey, can someone please explain the reason why do we maintain a map(headingElementsRef) inside a ref?

I'm also confused here...

Heisman2 commented 2 months ago

This was very helpful. I made and adjustment similar to wildky above so that when you scroll upward the heading changes, but I did it differently. I additionally pass in 'activeId' to useIntersectionObserver and then include this code:

if (visibleHeadings.length === 0) { const activeElement = headingElements.find((el) => el.id === activeId); const activeIndex = headingElements.findIndex( (el) => el.id === activeId ); const activeIdYcoord = activeElement?.getBoundingClientRect().y; if (activeIdYcoord && activeIdYcoord > 150 && activeIndex !== 0) { setActiveId(headingElements[activeIndex - 1].id); } }

Now if you scroll upwards and no headings are in the specified window (based on the rootMargin) then if the activeId is >150 px down the page it will shift the activeId to the next highest heading.