简体   繁体   中英

Display the first object in useState() array with data pulled from a database (React)

I am pulling a list of people from a database. When I map the array into many different components it works and the data gets displayed correctly. But when i want to access an individual element of the list trainer[0].id it says that the data does not exist. My guess is that the database isn't ready but how can I await that? Here is my code:

export default function TrainerInfo() {

    const [trainer, setTrainer] = useState([]);

    useEffect(() => {

        const trainerCollectionRef = collection(database, "trainer");

        const getTrainer = async () => {
            const data = await getDocs(trainerCollectionRef);
            setTrainer(data.docs.map((doc) => ({ ...doc.data(), id: doc.id })));
        };

        getTrainer();
    }, []);

    return (
        <div className="cms-stats">
            <TrainerSelection>
                {trainer.map(t => <Trainer id={t.id} key={t.id}>{t.name}</Trainer>)}
                // works
            </TrainerSelection>
            <Info id={trainer[0].id} name={trainer[0].name} status={trainer[0].status} image={trainer[0].image} key={trainer[0].id}/>
            // does not work
        </div>
    )
}

Thanks

The problem here is is that your code renders the component before the data is ready. You first need to check if the data is ready in your render process before you render elements where data access is needed.

            <TrainerSelection>
                {trainer.map(t => <Trainer id={t.id} key={t.id}>{t.name}</Trainer>)}
                // works
            </TrainerSelection>
            { trainer.length > 0 && 
                <Info id={trainer[0].id} name={trainer[0].name} status={trainer[0].status} image={trainer[0].image} key={trainer[0].id}/>
            }

With this code react will first check if trainer is true (in this case if the array is not empty in js an empty array is false). If the array is empty js will skip the render check, because javascript evaluates statements lazely, you can read more about it here .

Else the Info component will render.

In this case the TrainerSelection component doesn't throw an error, because you used the map method. So when the array is empty at the first render nothing will render, but when the state is updated the component is rerendered and you don't notice the difference.

This is one way to dit it but you could also use another useState variable to track if the data can be displayed.

EDIT: changed { trainer && ... to { trainer.length > 0 && .. . Not sure why it would matter in this case but it solved the issue.

<Info id={trainer[0].id} name={trainer[0].name} status={trainer[0].status} image={trainer[0].image} key={trainer[0].id}/>

There is no map function for this line.

Keep this in a map function as you have done just above and it should work

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM