Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use forwardRef with FunctionComponent in React Native using TypeScript

I've looked at many of the docs and examples but I still can't seem to quite understand how to use forwardRef with a functional component with TypeScript in React Native. Below is an example where I create a MyCustomComponent with a custom function that I try to call from the parent by creating a ref. However, since the ref is incorrectly defined and null, I obviously get an error message telling me that the function doesn't exist. Please help me understand how to properly use forwardRef in React Native. Thanks in advance!

interface MyCustomComponentProps {
  title: string
}

const MyCustomComponent: React.FunctionComponent<MyCustomComponentProps> = React.forwardRef((props, ref) => {
  const coolAlert = () => {
    Alert.alert('Hey!', 'This was called from MyCustomComponent')
  }
  return (
    <View>
      <Text>{props.title}</Text>
    </View>
  )
})

export default function App () {
  const MyCustomComponentRef = useRef()
  return (
    <SafeAreaView>
      <MyCustomComponent ref={MyCustomComponentRef} title='Hello World' />
      <TouchableOpacity
        onPress={() => {
          MyCustomComponentRef.coolAlert()
        }}>
        <Text>Click Me</Text>
      </TouchableOpacity>
    </SafeAreaView>
  )
}
like image 363
Harrison Avatar asked Oct 22 '20 18:10

Harrison


People also ask

How do you use React forwardRef in functional components?

Here's the code for doing so: import React, { useState, useRef, forwardRef } from 'React'; const Input = forwardRef((props, ref) => { return <input ref={ref} {... props} />; }); const App = () => { const inputRef = useRef(null); const [value, setValue] = useState(''); const onInputChange = (e) => { e.

How do I import forwardRef into React?

On this case, we need to change the Input Component to use the forwardRef. import React, { forwardRef } from "react"; const Input = (props, ref) => <input ref={ref} type="text" style={style} />; export default forwardRef(Input);

What is forwardRef in React native?

The forwardRef method in React allows parent components to move down (or “forward”) refs to their children. ForwardRef gives a child component a reference to a DOM entity created by its parent component in React. This helps the child to read and modify the element from any location where it is used.


1 Answers

Forwarding the Ref

Refs can be really confusing because there are multiple ways to handle them and because people aren't aware of the difference between the ref object (React.MutableRefObject or React.RefObject) and the ref value, which is stored on the .current property of the ref object. You've made that mistake here, along with some missing or incorrect typescript types.

useRef<T> is a generic hook where the value T tells up what type of value will be stored. We need to tell App that we intend to store something with a coolAlert method. Actually we'll see later on that we need our ref to be immutable so we we'll use createRef<T> instead.

interface MyRef {
  coolAlert(): void;
}

const MyCustomComponentRef = createRef<MyRef>();

When we call onPress, we need to access the current value of the ref object. By adding the generic to createRef, typescript already knows that this value is either MyRef or undefined. We can call coolAlert with the optional chaining ?. operator.

onPress={() => MyCustomComponentRef.current?.coolAlert()}

Now we need to do some work on MyCustomComponent. You've erred by assigning it the type React.FunctionComponent<MyCustomComponentProps> because a function component doesn't have the knowledge about ref forwarding that we need.

function forwardRef<T, P = {}>(Component: RefForwardingComponent<T, P>): ForwardRefExoticComponent<PropsWithoutRef<P> & RefAttributes<T>>;

The type for MyCustomComponent should be that complicated return type from forwardRef. But we don't need to assign that type ourselves, we just need to pass the generics T and P to the forwardRef function call. T is the type of the ref and P is the type of the props.

const MyCustomComponent = React.forwardRef<MyRef, MyCustomComponentProps>(...

Ok so we got rid of all the typescript errors! Yay! Except...hold up. It doesn't actually do anything. All of that and it still doesn't work. I hate refs. Refs are bad.

Using the Ref

We forwarded the ref to MyCustomComponent, who now has access to the forwarded ref and can attach it to a DOM component. But we don't want it attached to the DOM element, we want it attached to MyCustomComponent. But we can't really do that.

By default, you may not use the ref attribute on function components because they don’t have instances [docs]

We have to make use of a hook called useImperativeHandle which feels like a hack solution and even the docs say "don't do this". Yup, I hate refs.

useImperativeHandle customizes the instance value that is exposed to parent components when using ref. As always, imperative code using refs should be avoided in most cases. useImperativeHandle should be used with forwardRef. [docs]

We have to expose our coolAlert method through useImperativeHandle.

useImperativeHandle(ref , () => ({coolAlert}));

And now it actually works, finally!

like image 150
Linda Paiste Avatar answered Sep 20 '22 12:09

Linda Paiste