0

I am new to all this. The output of my code should display a list of selected people (residents) saved in a firestore.

Because I retrieve the documents from Firestore using an async-await, and then want to filter them based on a search query, I have used Promise.all() followed by .then() before returning the final list, residenceDocs.

In the below code, I use .map() to perform a DisplayResident() function, but this errors, saying it breaks the rule of hooks (DisplayResident() has various hooks in it!).

If I try to move the mapping of the residenceDocs outside the .then(), the result tries to display before the promise resolves and I get an empty array (i.e. nothing displays).

I had a go at using a custom hook to bypass the issue, but that didn't work.

My question can be summed up as: How do I call a function containing hooks on the result of a promise?

const ResidentList = () => {
    const [searchQuery, setSearchQuery] = React.useState('');
    const { currentUserData } = useAuth();

    const resTest = () => {
        const residences = currentUserData.userDocRef.docs[0]._document.data.value.mapValue.fields.residences.arrayValue.values;
        let residenceDocs = [];
        let residentNames = [];
        let isQueried = [];

        const promise1 = Promise.resolve(
            residences.map(async (residence) => {
                let residenceId = residence.referenceValue.split('/').pop();
                const docRef = doc(db, 'residences', residenceId);
                await getDoc(docRef).then((result) => {
                    if (result.data().resident && result.data().resident.lastname) {
                        residenceDocs.push(result.data());
                        residentNames.push(result.data().resident.firstname + ' ' + result.data().resident.lastname);
                    } else {
                        console.log(`Missing out ${residenceId} as no registered resident is present at this address.`);
                    }
                });
            })
        );

        promise1.then(() => {
            console.log(residenceDocs);
            const dataFiltered = filterData(searchQuery, residentNames);
            for (let i = 0; i < dataFiltered.length; i++) {
                let tmpIndex = residentNames.findIndex((eachResidentName) => eachResidentName === dataFiltered[i]);
                isQueried.push(tmpIndex);
            }
            return residenceDocs.map((eachResident, index) => DisplayResident(eachResident, index, isQueried));
        });
    };

    return (
        <MainCard style={cardStyle} title="Choose resident from list:">
            <Grid container spacing={2} paddingBottom={2}>
                <Grid item lg={10} xs={7}>
                    <SearchBar searchQuery={searchQuery} setSearchQuery={setSearchQuery} />
                </Grid>
            </Grid>
            {resTest()}
        </MainCard>
    );
};
skyboyer
  • 22,209
  • 7
  • 57
  • 64
Tallie
  • 1
  • Given `DisplayResident` is a component, you should not call it as a function, but let it be rendered by returning a jsx element: `` – Bergi Oct 09 '22 at 21:56
  • Thank you so much! And for the quick response. That removes the error (so many hours wasted...). However, the results don't display. That is a mystery. Unless you can instantly see why, I'll explore that further myself. – Tallie Oct 09 '22 at 22:05
  • See the 5 questions I linked at the top. You will need to render something while the documents are loading, then you will need to change the state of your component to store the results, then you can render the results when they're available. – Bergi Oct 09 '22 at 22:05
  • Thank you, I'll check out the materials :) – Tallie Oct 09 '22 at 22:08

0 Answers0