I have a function component that takes a variable amount of child (forwardRef) function components. What I would like to achieve is having a ref to each of the child components for animations when a child component is clicked. I have a semi-working solution by creating an array of refs and then cloning all the children and passing an indexed ref to each of them. The only issue is that all of the refs in the index point to the same (last) child.
Here are my components:
const Navbar = ({children}) => {
const [activeLink, setActiveLink] = useState(0);
const linkRefs = Array(children.length).fill(React.createRef(null));
const handleActiveLinkChange = (index) => {
setActiveLink(index);
console.log(linkRefs[index].current);
}
return (
<nav>
{React.Children.map(children, (child, index) => React.cloneElement(child, {index: index, active: index === activeLink, handleActiveLinkChange, key: "child" + index, ref: linkRefs[index]}))}
</nav>
)
}
const Link = React.forwardRef(({children, active, index, handleActiveLinkChange}, ref) => {
return (
<a href="#" style={linkStyle} onClick={() => handleActiveLinkChange(index)} ref={ref}>
{active ? <b>{children}</b> : children}
</a>
)
});
And assuming I use the components in the following way:
<Navbar>
<Link>One</Link>
<Link>Two</Link>
<Link>Three</Link>
<Link>Four</Link>
<Link>Five</Link>
</Navbar>
I expect the refs to be:
| Ref array index | Ref current |
|---|---|
| 0 | One |
| 1 | Two |
| 2 | Three |
| 3 | Four |
| 4 | Five |
But the refs I get are:
| Ref array index | Ref current |
|---|---|
| 0 | Five |
| 1 | Five |
| 2 | Five |
| 3 | Five |
| 4 | Five |
I'm assuming it's something to do with variable scope but I just can't figure out the cause of the issue. I've tried many variations of loops and functions but I'd rather understand the cause than blindly try to find a solution.
The issue is with the following line. It creates only one ref and all the array indices refer to that single ref.
const linkRefs = Array(children.length).fill(React.createRef(null));
Instead of the above use the following line which creates new refs for each child as you expect.
const linkRefs = Array.from({ length: children.length }, () =>
React.createRef(null)
);