Come usare forwardRef con FunctionComponent in React Native usando TypeScript

Oct 22 2020

Ho esaminato molti dei documenti e degli esempi, ma non riesco ancora a capire bene come usarlo forwardRefcon un componente funzionale con TypeScript in React Native. Di seguito è riportato un esempio in cui creo un MyCustomComponentcon una funzione personalizzata che provo a chiamare dal genitore creando un rif. Tuttavia, poiché il riferimento è definito in modo errato e null, ovviamente, ricevo un messaggio di errore che mi dice che la funzione non esiste. Per favore aiutami a capire come usare correttamente forwardRefin React Native. Grazie in anticipo!

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

Risposte

3 LindaPaiste Oct 22 2020 at 23:27

Inoltro del Ref

I ref possono essere davvero fonte di confusione perché ci sono molti modi per gestirli e perché le persone non sono consapevoli della differenza tra l'oggetto ref ( React.MutableRefObjecto React.RefObject) e il valore ref, che è memorizzato nella .currentproprietà dell'oggetto ref. Hai fatto quell'errore qui, insieme ad alcuni tipi di dattiloscritti mancanti o errati.

useRef<T>è un hook generico in cui il valore Tindica quale tipo di valore verrà memorizzato. Dobbiamo dire Appche intendiamo memorizzare qualcosa con un coolAlertmetodo. In realtà vedremo più avanti che abbiamo bisogno che il nostro ref sia immutabile, quindi useremo createRef<T>invece.

interface MyRef {
  coolAlert(): void;
}

const MyCustomComponentRef = createRef<MyRef>();

Quando chiamiamo onPress, dobbiamo accedere al valore corrente dell'oggetto ref. Aggiungendo il generico a createRef, il dattiloscritto sa già che questo valore è MyRefo undefined. Possiamo chiamare coolAlertcon l' ?.operatore di concatenamento opzionale .

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

Ora dobbiamo lavorare su MyCustomComponent. Hai commesso un errore assegnandogli il tipo React.FunctionComponent<MyCustomComponentProps>perché un componente funzione non ha la conoscenza dell'inoltro ref di cui abbiamo bisogno.

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

Il tipo per MyCustomComponentdovrebbe essere quel complicato tipo restituito da forwardRef. Ma non abbiamo bisogno di assegnare quel tipo noi stessi, abbiamo solo bisogno di passare i generici Te Palla forwardRefchiamata di funzione. Tè il tipo di riferimento ed Pè il tipo di oggetti di scena.

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

Ok, quindi ci siamo sbarazzati di tutti gli errori di battitura ! Sìì! Tranne che ... resisti. In realtà non fa nulla . Tutto questo e ancora non funziona. Odio gli arbitri. Gli arbitri sono pessimi.

Utilizzando il Ref

Abbiamo inoltrato il riferimento a MyCustomComponent, che ora ha accesso al riferimento inoltrato e può collegarlo a un componente DOM. Ma non vogliamo che sia attaccato all'elemento DOM, lo vogliamo attaccato MyCustomComponent. Ma non possiamo davvero farlo.

Per impostazione predefinita, non puoi utilizzare l'attributo ref sui componenti della funzione perché non hanno istanze [docs]

Dobbiamo usare un hook chiamato useImperativeHandleche sembra una soluzione hack e anche i documenti dicono "non farlo". Sì, odio gli arbitri.

useImperativeHandle personalizza il valore dell'istanza esposto ai componenti padre quando si utilizza ref. Come sempre, il codice imperativo che usa refs dovrebbe essere evitato nella maggior parte dei casi. useImperativeHandle deve essere utilizzato con forwardRef. [documenti]

Dobbiamo esporre il nostro coolAlertmetodo attraverso useImperativeHandle.

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

E ora funziona davvero , finalmente!