简体   繁体   中英

How to get the return value of parent function to child component in react (Using props)

I have created a simple react app using functional components. The parent component is 'Sites' while the child is 'View Sites'. I have this function in my parent (Sites component)

function getSitesDB() {
    ref.onSnapshot((querySnapshot) => {
        const items = [];
        querySnapshot.forEach((doc) => {
            items.push(doc.data());
        }); 
        return items;
    });
}

I want to call this function from my child (view sites) component and get the return value to it. for that I have rendered my child component as this,

<Route exact path="/sites">
    <ViewSites getSitesDB={getSitesDB}></ViewSites>
</Route>

And called the function using props from the child component as this,

useEffect(() => {
    setLoading(true);
    const returnVal = props.getSitesDB();

    setLoading(false);
}, []);

I get this returnVal variable as undefined, but this function calls the parent function properly. Just want to know how to get the return value back. Please help me as I'm new to react.

currently, you are not returning anything from the getSitesDB() function, and you can't because you only get access to querySnapshot when the callback is called, you can try returning a promise from getSitesDB() and resolve it with items when the callback is called, something like this:

function getSitesDB() {
    return new Promise((resolve, reject)=> {
        ref.onSnapshot((querySnapshot) => {
            const items = [];
            querySnapshot.forEach((doc) => {
            items.push(doc.data());
            }); 
            resolve(items);
        });

    })
}

and then in your useEffect() , chain a .then() to the function like this,

useEffect(() => {
    setLoading(true);
    props.getSitesDB().then(returnVal => {
        // set returnVal to some state here so you can use it somewhere else in your component
        // =>> setState(returnVal)
        setLoading(false);
    })
}, []);

I am not sure if it will work fine, because I don't know where that 'onSnapshot' comes from, it looks like it listens for an event and calls the callback each time(may be more than once) some change happens, in that case it might throw an error as promise would've already be resolved on initial call.

read more on promises here at mdn

When calling the getSitesDB you should return the items that you got from firestore's onSnapshot function. the onSnapshot function ignores your return items...

To fetch the data you should do something like this:

function getSitesDB() {
  return new Promise((resolve, reject) => {
    const items = [];
    ref.onSnapshot((querySnapshot) => {
      querySnapshot.forEach((doc) => items.push(doc.data()));
      resolve(items);
    });
  });
}

To support unmount on your useEffect you should do something like this:

useEffect(() => {
  let canceled = false;
  const fetchData = async () => {
    setLoading(true);
    const sitesData = await getSitesDB();
    if (!canceled) {
      setSitesData(sitesData);
      setLoading(false);  
    }
  }

  fetchData();
  return () => {
    canceled = true;
  }
}, [getSitesDB]);

You can achive with many ways. 1 Redux 2 Context API 3 Traditional way (Pass that function as props in Parent Component)

When ever you get function as a props in component You can use like below mention way

useEffect(() => { const returnValue = props.funtionMentionInParent(); console.log(returnValue) }, []);

Thank you

In Parent use state to keep the result of function

import React, { useState } from "react";
const [sitesDB, setSitesDB] = useState(null);

Also use setSitesDB(items) to update the value in the state.

function getSitesDB() {
    ref.onSnapshot((querySnapshot) => {
        const items = [];
        querySnapshot.forEach((doc) => {
            items.push(doc.data());
        }); 
        setSitesDB(items); // here state is updated
        return items;
    });
}

Then pass the function and the state to the Child

<Route exact path="/sites">
    <ViewSites getSitesDB={getSitesDB} sitesDB={sitesDB}></ViewSites>
</Route>

Call the function in Child. And use state sitesDB where you need.

useEffect(() => {
    setLoading(true);
    props.getSitesDB();

    setLoading(false);
}, []);

console.log(props.sitesDB);

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