Hooks, useImperativeMethods and multiple refs
See original GitHub issueI am not sure where to post this question, feel free to delete it if it doesn’t belong here.
Here is a small Accordion with AccordionPanels. It uses hooks to manage state and when some panel is opened we need to scroll to it, so we need a ref.
My question is: Is this how hooks are supposed to be used? Do you see some problems with this approach?
App.js
function App() {
const panels = [
'Panel 1',
'Panel 2',
'Panel 3'
];
const [currentIndex, onClick, refs] = useAccordion(panels.length);
return <Accordion>
{panels.map((panel, index) => (
<AccordionPanel
ref={refs[index]}
key={index}
label={panel}
isOpen={currentIndex === index}
onClick={() => onClick(index)}
/>
))}
</Accordion>;
}
Accordion.js
function useAccordion(panelsCount) {
const [currentIndex, setCurrentIndex] = useState(undefined);
let refs = {};
for (let i = 0; i <= panelsCount; i++) {
refs[i] = createRef();
}
useEffect(() => {
if (currentIndex !== undefined) {
refs[currentIndex].current.scrollTo();
}
}, [currentIndex]);
function onClick(newIndex) {
setCurrentIndex(currentIndex === newIndex ? undefined : newIndex);
}
return [currentIndex, onClick, refs];
}
const AccordionPanel = React.forwardRef((props, ref) => {
const containerRef = useRef();
useImperativeMethods(ref, () => ({
scrollTo: () => console.info('do scrolling')
}));
return <div onClick={props.onClick} ref={containerRef}>
{props.label}, {props.isOpen && 'open'}
</div>;
});
function Accordion(props) {
return <div>{props.children}</div>;
}
Issue Analytics
- State:
- Created 5 years ago
- Comments:16 (7 by maintainers)
Top Results From Across the Web
How can I use multiple refs for an array of elements with hooks?
As you cannot use hooks inside loops, here is a solution in order to make it work when the array changes over the...
Read more >Hooks API Reference - React
This page describes the APIs for the built-in Hooks in React. ... which is more suited for managing state objects that contain multiple...
Read more >How to add multiple refs to one useRef() hook | Eliaslog.pw
The ref property on our JSX-div can take a function where the current element is passed in as the first argument. Our refs...
Read more >Intro to React Hooks | CSS-Tricks
useImperativeMethods customizes the instance value that is exposed to parent components when using ref . As always, imperative code using refs ...
Read more >Get Hooked on React! | Object Computing, Inc.
Hooks make it easier to reuse state logic between multiple components. In most cases this removes ... This is demonstrated in the "Ref...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
I guess there is currently no true idiomatic way of dealing with sets of refs. The issue is that the set itself grows or shrinks between updates but the true value changes in the commit phase as a side-effect. I think for most cases, you just want to change the set as a side-effect too. You can do that simply by mutating a persistent Map.
If you’re dealing with raw children and want a ref to each item in the list, you should use the React.Children helpers to create a list where each item has a unique key.
Then you can attach a ref to that which stores the result in a Map based on that key.
If it is a custom data structure like the example above then you can do the same thing but that data structure needs a key as part of it:
This doesn’t preserve old refs if
panelsCount
changes (they’ll be reattached after the current render commits), but you can useuseMemo
for this: