user944513
user944513

Reputation: 12729

how to create ref in functional component in react js?

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) enter image description here

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
  });

I am getting this output enter image description here

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

Answers (2)

Linda Paiste
Linda Paiste

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

TopW3
TopW3

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

Related Questions