Jak używać forwardRef z FunctionComponent w React Native przy użyciu TypeScript

Oct 22 2020

Przejrzałem wiele dokumentów i przykładów, ale nadal nie mogę całkiem zrozumieć, jak używać forwardReffunkcjonalnego komponentu z TypeScript w React Native. Poniżej znajduje się przykład, w którym tworzę funkcję MyCustomComponentz niestandardową funkcją, którą próbuję wywołać od rodzica, tworząc ref. Jednakże, ponieważ ref jest nieprawidłowo zdefiniowany i nulloczywiście otrzymuję komunikat o błędzie informujący mnie, że funkcja nie istnieje. Proszę, pomóż mi zrozumieć, jak prawidłowo używać forwardRefw React Native. Z góry dziękuję!

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

Odpowiedzi

3 LindaPaiste Oct 22 2020 at 23:27

Przekazywanie numeru ref

Refs mogą być naprawdę mylące, ponieważ istnieje wiele sposobów ich obsługi i ponieważ ludzie nie są świadomi różnicy między obiektem ref ( React.MutableRefObjectlub React.RefObject) a wartością ref, która jest przechowywana we .currentwłaściwości obiektu ref. Popełniłeś ten błąd, razem z brakującymi lub nieprawidłowymi typami maszynopisów.

useRef<T>jest ogólnym punktem zaczepienia, w którym wartość Tmówi, jaki typ wartości będzie przechowywany. Musimy powiedzieć App, że zamierzamy coś przechowywać za pomocą coolAlertmetody. Właściwie zobaczymy później, że potrzebujemy, aby nasz ref był niezmienny, więc użyjemy createRef<T>zamiast tego.

interface MyRef {
  coolAlert(): void;
}

const MyCustomComponentRef = createRef<MyRef>();

Kiedy wywołujemy onPress, musimy uzyskać dostęp do bieżącej wartości obiektu ref. Dodając do rodzajową createRef, maszynopis już wie, że ta wartość jest albo MyRefalbo undefined. Możemy zadzwonić coolAlertz opcjonalnym ?.operatorem łańcuchowym .

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

Teraz musimy trochę popracować MyCustomComponent. Błąd, przypisując mu typ, React.FunctionComponent<MyCustomComponentProps>ponieważ składnik funkcji nie ma wiedzy o przekazywaniu referencji, której potrzebujemy.

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

Typ dla MyCustomComponentpowinien być tym skomplikowanym typem zwracanym z forwardRef. Ale nie musimy przypisać tego typu siebie, po prostu trzeba przejść rodzajowych Ti Pdo forwardRefwywołania funkcji. Tjest typem odniesienia i Ptypem rekwizytów.

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

Ok, więc pozbyliśmy się wszystkich błędów maszynopisu ! Yay! Tylko że ... poczekaj. W rzeczywistości nic nie robi . To wszystko i nadal nie działa. Nienawidzę referencji. Odniesienia są złe.

Korzystanie z ref

Przekazaliśmy ref do MyCustomComponent, który ma teraz dostęp do przesłanego ref i może dołączyć go do komponentu DOM. Ale nie chcemy, aby był on dołączony do elementu DOM, chcemy go dołączyć MyCustomComponent. Ale tak naprawdę nie możemy tego zrobić.

Domyślnie nie możesz używać atrybutu ref w komponentach funkcji, ponieważ nie mają one instancji [docs]

Musimy skorzystać z wywoływanego useImperativeHandlehooka, który wydaje się być rozwiązaniem hakerskim, a nawet doktorzy mówią „nie rób tego”. Tak, nienawidzę referencji.

useImperativeHandle dostosowuje wartość instancji, która jest widoczna dla komponentów nadrzędnych podczas korzystania z ref. Jak zawsze, w większości przypadków należy unikać bezwzględnego kodu używającego referencji. useImperativeHandle powinno być używane z forwardRef. [dokumenty]

Musimy ujawnić naszą coolAlertmetodę useImperativeHandle.

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

I wreszcie wreszcie działa !