Search code examples
reactjsreact-functional-componentuse-ref

How can i call a function on a React functional class?


I want to call a function on a class by accessing useRef.current same way I can with class components and DOM objects. I know all the rules about DOM and class instances etc which makes useRefs possible but how do I call myfunctioncomponent.method()?

Sandbox demonstrating the error:

https://codesandbox.io/s/class-vs-function-useref-zjee5?file=/src/App.js

error:

Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?

code:

export const App = () => {
  let functionref = useRef(null);
  let domref = useRef(null)
  let classref = useRef(null);

  useEffect(() => {
    console.log(functionref); // fails :(
    console.log(domref); // works! 
    console.log(classref); // works !
    classref.current.callme(); // works!
    classref.current.callme(); // fails!
  }, []);
  return (
    <>
      <ClassComponent ref={classref}/>
      <div ref={domref}>This is a DOM node</div>
      <FunctionComponent ref={functionref} />
    </>
  );
};

class ClassComponent extends React.Component {
  callme() {
    console.log("ClassComponent function called!");
  }
  render() {
    return (
      <p>This is a class component</p>
     )
  }
}

const FunctionComponent = () => {
  const callme = () => {
    console.log("function called!");
  }

  return (
   <p>This is a function component</p>
  )
}

perhaps i am trying to bend the rules too much or introducing an anti-pattern(?) if so Id greatly appreciate advice on the correct way of accessing functions and properties inside functional components, or alternatives.

any help appreciated.


Solution

  • For what you're trying to do you need to use a forwardRef so that the ref is passed to the functional component, I put an example snippet below. In class components a ref lets you access the class components methods, but when you do that with a react functional component that does not happen. Instead you just get back the ref and it's up to you to decide what will live in the ref. This is why in snippet below you need to add ref.current = { callme } so that the callme method will be available when called as functionref.current.callme().

    const FunctionComponent = React.forwardRef((_props, ref) => {
      const callme = () => {
        console.log("function called!");
      };
    
      ref.current = { callme };
    
      return <p>This is a function component</p>;
    });
    

    Here's a codesandbox of that