Reputation: 12729
I am trying to create ref in functional component .But getting different output as compare to to class based component
.
here is simple class based component
.In class based component I am getting correct refs
here is class based component https://stackblitz.com/edit/react-vh86ou?file=src%2Ftabs.js
see ref mapping (correct ref mapping)
Same mapping I am trying to do with functional component but getting different output why ?
here is my function component https://stackblitz.com/edit/react-nagea2?file=src%2FApp.js
export default function App() {
useEffect(() => {
console.log('---', tabRefs);
}, []);
const getTabProps = ({ title, key, selected, tabIndex }) => ({
selected,
children: title,
key: tabPrefix + key,
id: tabPrefix + key,
ref: e => (tabRefs[tabPrefix + key] = e),
originalKey: key
});
Why I am getting Ref from HTMLLIELEMENT instead of TAB
component ?
Update :
I am trying to get offsetWidth
still not able to get
https://stackblitz.com/edit/react-nagea2?file=src%2FApp.js
useEffect(() => {
console.log('---', tabRefs);
Object.keys(tabRefs).forEach(key => {
console.log(key);
if (tabRefs[key]) {
const width = tabRefs[key].tab.offsetWidth;
console.log(width);
}
});
}, []);
Upvotes: 4
Views: 15974
Reputation: 42160
As explained by @TabW, function components do not have refs. But you don't need a ref to the Tab
component itself. You can get the offsetWidth
of the underlying li
element just by forwarding the ref, without having to use useImperativeHandle
.
Attach your forwarded ref directly on the li
:
const Tab = React.forwardRef(({ children }, ref) => {
return <li ref={ref}>{children}</li>;
});
And remove the .tab
property from where you access it.
Upvotes: 2
Reputation: 1527
You can't add the ref attribute to functional component for reasons as mentioned here. You can use forwardRef function combined with useImperativeHandle hook to emulate class component ref, but you can't add ref to your Tab component as long as Tab is a function component.
For example, you can add some code to your Tab component like below.
const Tab = React.forwardRef(({ children }, ref) => {
const liRef = useRef(null);
React.useImperativeHandle(ref, () => ({
tab: liRef.current
}));
return <li ref={liRef}>{children}</li>;
});
export default Tab;
If you want to store all refs of all Tab component and call some functions of it later, you can add functions inside useImperativeHandle hook.
Upvotes: 3