I have a use-case where I need to assign a unique and persistent unique id to each HTML tag in my page.
Background:
I have created a block element so everything in the webpage is a <Block />
element now.
The block element is defined like this
export const Block = ({ children, className = "", id = "", ...props }) => {
const handleClick = () => {
console.log("Clicks working");
};
const prevChildrenRef = useRef(children);
useEffect(() => {
if (prevChildrenRef.current !== children) {
console.log(`Content changed for id ${id}`);
prevChildrenRef.current = children;
}
}, [children, id]);
console.log(`Rendering Block with ID: ${id}`);
return (
<div className={`${className} hover`} id={id} onClick={handleClick} {...props}>
{children}
</div>
);
};
This is how I am using my block element, similarly in the whole page, everything is a Block at the atomic level.
usage:
<Block className="flex flex-col items-start space-y-1 text-start">
<Block>
<Block className="text-4xl font-bold">{start.name}</Block>
<Block className="py-2 text-2xl">{start.headline}</Block>
</Block>
</Block>
I would want to create a unique and persistent id for each block so even after page refresh, it would remain consistent.
What I have tried:
I tried naming every section’s block using recursion, so the top root element will have unique id as the section name, for example here, start, as we go down the children, they will be have the id <parent_id>_1, <parent_id>_2, <parent_id>_1_1 (parent’s grandchildren) and so on.
Here is the code.
export const assignIds = (element, idPrefix = prefix) => l{
let counter = 1;
const childrenWithIds = React.Children.map(element.props.children, (child) => {
if (React.isValidElement(child)) {
const newIdPrefix = `${idPrefix}_${counter}`;
counter++;
return React.cloneElement(
child,
{ id: newIdPrefix, key: newIdPrefix },
assignIds(child, newIdPrefix),
);
}
return child;
});
return React.cloneElement(element, { id: idPrefix }, childrenWithIds);
};
While this approach works, the issue I am facing is, when the value of {start.name} or {start.headline} is changed, I only want to capture the id of that block which it is under,and not the parent or grandparent. Right now with my code implementation, it is also triggering the console – console.log(`Content changed for id ${id}`); (in the block)
defined inside useEffect for parent as well as grandparents.
Where I need help
Ultimately, what I want is to capture the id of only the block which is being changed, without involving any ancestors so I can dynamically pass the CSS to change its style dynamically.
2
Answers
You can solve this problem by using a combination of React’s
useRef
anduseEffect
hooks. Here’s the plan:Block
component, create auseRef
hook to store the initial children.useEffect
hook, compare the current children with the initial children. If they are different, log the id of the current block and update the initial children ref.assignIds
function, clone the child elements and assign them new ids based on their index in the children array. Also, pass the new id to theBlock
component.Here’s the updated code:
This code will ensure that only the
Block
whose content has changed will log its id, not its ancestors. This is because theuseEffect
hook in theBlock
component only triggers when its own children change, not when the children of its ancestors change.To achieve your goal of capturing the ID of only the block that has changed without involving any ancestors, you can update your
Block
component and theassignIds
function. The key is to keep track of the previous state of children within the component itself and ensure that each block only monitors its direct children.Here’s a revised approach:
assignIds
function.useEffect
hook.Updated
Block
ComponentFirst, update your
Block
component to handle only direct children changes:Updated
assignIds
FunctionUpdate the
assignIds
function to ensure unique and persistent IDs:Usage Example
Here’s how you can use the updated
Block
component andassignIds
function in your application:Explanation
Block Component:
useRef
to keep track of the previous children.useEffect
hook checks if the current children are different from the previous children and logs the ID if they are.assignIds Function:
idPrefix
.Usage Example:
assignIds
function is called to assign IDs to the content blocks.This approach ensures that each block has a unique and persistent ID and only logs changes for direct children, without involving any ancestors.