Jeremy Belolo
Jeremy Belolo

Reputation: 4539

React Native - focus the first touchable in a list

I'm trying to get the first TouchableOpacity in a FlatList to get focus after render. I tried to use refs and trigger focus from useEffect but I can't figure it out.

Here is the code:

import React, {useRef, useEffect} from "react";
import {FlatList, Text, TouchableOpacity, View} from "react-native";

const MyScreen = () => {
    const refs = useRef([]);

    useEffect (() => {
        refs.current[0].focus()
    }, []);

    const setFocusedElement = (element) => {
        console.log(element);
    }

    return (
        <View>
            <FlatList
                data={[1, 2, 3]}
                keyExtractor={(item) => item}
                renderItem={({ item, index }) => {
                    return (
                        <TouchableOpacity ref={el => refs.current[index] = el} onFocus={() => setFocusedElement(item)}>
                            <View><Text>{item}</Text></View>
                        </TouchableOpacity>
                    );
                }}
            />
        </View>
    );
}

export default MyScreen;

I'm getting an error like so : "TypeError: undefined is not an object (evaluating 'refs.current[0].focus')"

[EDIT] after a small edit based on @drew-reese great answer, the ref is working, but the focus still isn't.

[EDIT 2] Here is a snack example of the issue : https://snack.expo.dev/@jerrybels/calm-ramen

Upvotes: 1

Views: 1652

Answers (1)

Drew Reese
Drew Reese

Reputation: 202667

refs itself is a React ref, but you don't appear to be setting the child refs by index correctly. You should still reference refs.current to update the ref value.

ref={el => refs.current[index] = el}

You may find you have better luck explicitly creating refs for each child component being rendered, and pass these as the ref versus using the callback syntax.

const refs = useRef([]);

refs.current = data.map((_, i) => refs.current[i] ?? createRef());

useEffect (() => {
  refs.current[0].current.focus();
}, []);

...

<FlatList
  data={data}
  keyExtractor={(item) => item}
  renderItem={({ item, index }) => (
    <TouchableOpacity ref={refs.current[index]}>
      <View><Text>{item}</Text></View>
    </TouchableOpacity>
  )}
/>

Upvotes: 1

Related Questions