Comment utiliser forwardRef avec FunctionComponent dans React Native à l'aide de TypeScript
J'ai regardé de nombreux documents et exemples, mais je n'arrive toujours pas à comprendre comment utiliser forwardRefavec un composant fonctionnel avec TypeScript dans React Native. Voici un exemple où je crée un MyCustomComponentavec une fonction personnalisée que j'essaye d'appeler du parent en créant un ref. Cependant, comme la référence est mal définie et null, j'obtiens évidemment un message d'erreur m'indiquant que la fonction n'existe pas. S'il vous plaît, aidez-moi à comprendre comment utiliser correctement forwardRefdans React Native. Merci d'avance!
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>
)
}
Réponses
Transférer la référence
Les références peuvent être vraiment déroutantes car il existe plusieurs façons de les gérer et parce que les gens ne sont pas conscients de la différence entre l'objet ref ( React.MutableRefObjectou React.RefObject) et la valeur ref, qui est stockée sur la .currentpropriété de l'objet ref. Vous avez fait cette erreur ici, ainsi que certains types de dactylographie manquants ou incorrects.
useRef<T>est un hook générique où la valeur Tindique quel type de valeur sera stocké. Nous devons dire Appque nous avons l'intention de stocker quelque chose avec une coolAlertméthode. En fait, nous verrons plus tard que nous avons besoin que notre référence soit immuable, nous allons donc l'utiliser à la createRef<T>place.
interface MyRef {
coolAlert(): void;
}
const MyCustomComponentRef = createRef<MyRef>();
Lorsque nous appelons onPress, nous devons accéder à la valeur actuelle de l'objet ref. En ajoutant le générique à createRef, dactylographié sait déjà que cette valeur est soit MyRefou undefined. Nous pouvons appeler coolAlertavec l' ?.opérateur de chaînage optionnel .
onPress={() => MyCustomComponentRef.current?.coolAlert()}
Maintenant, nous devons travailler sur MyCustomComponent. Vous vous êtes trompé en lui attribuant le type React.FunctionComponent<MyCustomComponentProps>car un composant de fonction ne possède pas les connaissances nécessaires sur le transfert de référence.
function forwardRef<T, P = {}>(Component: RefForwardingComponent<T, P>): ForwardRefExoticComponent<PropsWithoutRef<P> & RefAttributes<T>>;
Le type de MyCustomComponentdevrait être ce type de retour compliqué de forwardRef. Mais nous n'avons pas besoin d'attribuer ce type nous-mêmes, nous devons juste passer les génériques Tet Pl' forwardRefappel de fonction. Test le type de la référence et Pest le type des accessoires.
const MyCustomComponent = React.forwardRef<MyRef, MyCustomComponentProps>(...
Ok donc nous nous sommes débarrassés de toutes les erreurs de dactylographie ! Yay! Sauf ... attendez. Cela ne fait rien . Tout ça et ça ne marche toujours pas. Je déteste les arbitres. Les références sont mauvaises.
Utilisation de la référence
Nous avons transmis la référence à MyCustomComponent, qui a maintenant accès à la référence transmise et peut la joindre à un composant DOM. Mais nous ne voulons pas qu'il soit attaché à l'élément DOM, nous voulons qu'il soit attaché MyCustomComponent. Mais on ne peut pas vraiment faire ça.
Par défaut, vous ne pouvez pas utiliser l’attribut ref sur les composants de fonction car ils n’ont pas d’instances [docs]
Nous devons utiliser un hook appelé useImperativeHandlequi ressemble à une solution de hack et même la documentation dit "ne faites pas ça". Ouais, je déteste les arbitres.
useImperativeHandle personnalise la valeur d'instance exposée aux composants parents lors de l'utilisation de ref. Comme toujours, le code impératif utilisant des références doit être évité dans la plupart des cas. useImperativeHandle doit être utilisé avec forwardRef. [docs]
Nous devons exposer notre coolAlertméthode à travers useImperativeHandle.
useImperativeHandle(ref , () => ({coolAlert}));
Et maintenant ça marche , enfin!