I'm trying to create a React component that scans through the elements of its child component and renders itself based on that.
Imagine I have many components, each with h1
, h2
, and p
tags. I would like to create a generic table of contents component that can be used as a parent component to these other components. The table of contents component would need to render the child page and then scan through it for the h1
/h2
tags and render to a table of contents.
So my question is how do I scan through the "DOM" of the child component after I've created it using React.createElement()
in the parent component?
Printing the result of this call, I only see an object with key
, props
, ref
, and type
attributes, which don't seem to fit the purpose.
CodePudding user response:
React.createElement doesn't actually create a DOM element you can access but rather an object that React understands how to convert into a DOM element when rendering. You probably want to add an effect that runs on re-render and scans through child elements. It will probably look something like this
function TableOfContents(_props) {
const { elements } = props;
useEffect(() => {
const childElements = document.getElementById("parent")?.children
// you could also possibly just use elements directly instead of getting the parent first
if (childElements) {
// do something with children elements
}
}, [elements])
return (
<div id="parent">
{props.elements.map(e => React.createElement(e))}
</div>
)
}
// usage of Component
<TableOfContents elements={['h1', 'h1', 'h2', 'p']} />
CodePudding user response:
I guess if you have control over the generation of those h1, p and other tags, then use that data source for your TOC generation algorithm.
For example, your content might be generated by a remote data source. If so, use the same data source instead of scanning DOM.
But if you don't have access to it, then you have to scan the Dom. To do it create a component and use the hook, useEffect
. In that hook you can run DOM queries like document.getElementsByTagName
function to find out those tags. The elements returned by functions in document object are real DOM elements not react vdom elements.
function TOC() {
let [tocItems, setTocItems] = useState ();
useEffect (()=> {
let els = document.getElementsByTagName('p');
// Do something with elements and set it for the state
// setTocItems ();
},[]);
return (
<div>{tocItems}</div>
);
}