首页 > 解决方案 > 如何使用 TypeScript 在 React Native 中使用 forwardRef 和 FunctionComponent

问题描述

我查看了许多文档和示例,但我似乎仍然不太了解如何forwardRef在 React Native 中使用带有 TypeScript 的功能组件。下面是一个示例,其中我创建了MyCustomComponent一个自定义函数,我尝试通过创建一个 ref 从父级调用该函数。但是,由于 ref 的定义不正确null,我显然会收到一条错误消息,告诉我该函数不存在。请帮助我了解如何forwardRef在 React Native 中正确使用。提前致谢!

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

标签: javascriptreactjstypescriptreact-nativereact-hooks

解决方案


转发参考

Refs 可能真的很令人困惑,因为有多种方法可以处理它们,而且人们不知道 ref 对象(React.MutableRefObjectReact.RefObject)和 ref 值之间的区别,ref 值存储在.currentref 对象的属性中。您在这里犯了这个错误,以及一些缺失或不正确的打字稿类型。

useRef<T>是一个通用钩子,其中值T告诉将存储什么类型的值。我们需要告诉App我们打算用coolAlert方法存储一些东西。实际上我们稍后会看到我们需要我们的 ref 是不可变的,所以我们将使用它createRef<T>

interface MyRef {
  coolAlert(): void;
}

const MyCustomComponentRef = createRef<MyRef>();

当我们调用 时onPress,我们需要访问 ref 对象的当前值。通过将泛型添加到createRef,打字稿已经知道这个值是MyRefor undefined。我们可以coolAlert使用可选的链接?.运算符进行调用。

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

现在我们需要对MyCustomComponent. 您错误地为其分配了类型React.FunctionComponent<MyCustomComponentProps>,因为函数组件不具备我们需要的关于 ref 转发的知识。

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

for 的类型MyCustomComponent应该是 from 的复杂返回类型forwardRef。但是我们不需要自己分配那个类型,我们只需要传递泛型和T函数调用。 是 ref的类型,是 props 的类型。PforwardRefTP

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

好的,所以我们摆脱了所有打字稿错误!耶!除了……等一下。它实际上并没有做任何事情。所有这些,它仍然不起作用。 我讨厌裁判。裁判很糟糕。

使用参考

我们将 ref 转发给MyCustomComponent,他现在可以访问转发的 ref 并可以将其附加到 DOM 组件。但是我们不希望它附加到 DOM 元素,我们希望它附加到MyCustomComponent. 但我们真的做不到。

默认情况下,您可能不会在函数组件上使用 ref 属性,因为它们没有实例[docs]

我们必须使用一个叫做 hack 的钩子useImperativeHandle,它感觉像是一个 hack 解决方案,甚至文档都说“不要这样做”。是的,我讨厌裁判。

useImperativeHandle 自定义使用 ref 时暴露给父组件的实例值。与往常一样,在大多数情况下应避免使用 refs 的命令式代码。useImperativeHandle 应该与 forwardRef 一起使用。[文档]

我们必须coolAlert通过useImperativeHandle.

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

现在终于可以正常工作了!


推荐阅读