0

I want to return my app as soon as data has been fetched. As long as it hasn't been, I want to display a black screen. Therefore I tried to return JSX after fetching the data, but I get the following error:

Functions are not valid as a React child. This may happen if you return a Component instead of from render. Or maybe you meant to call this function rather than return it.

function App() {

    return firebase.firestore().collection('projects').onSnapshot(snap => {
        let projects = [];
        snap.forEach(doc => {
            projects.push(doc.data())
        });
        return (
            <div className="App">
                <Router history={history}>
                    <ScrollToTop>
                        <Header/>
                        <Route path="/project/:name" component={Project}/>
                        <Route path="/about" component={About}/>
                        <div className="hs">
                            <Route path={["/", "/project/:name"]} exact component={() => <CartHolder projects={projects}/>}/>
                        </div>
                        <div className="hs-mobile">
                            <Route path="/" exact component={CartHolderMobile}/>
                        </div>
                    </ScrollToTop>
                </Router>
            </div>
        );
    });
}

What's the best way to do so?

Jan Hernandez
  • 4,414
  • 2
  • 12
  • 18
Tom
  • 3,672
  • 6
  • 20
  • 52
  • You need to return a `JSX` element. In addition: `useEffect` - https://reactjs.org/docs/hooks-reference.html#useeffect – norbitrial Jan 08 '20 at 20:25

2 Answers2

2

You will have to return <BlackScreen> until your api gives you a response. In addition to that

You will have to use useEffect. Please refer the similar answer here

function App() {
   const [projects, setProjects] = useState([]);
   useEffect(() => {

      if (!projects) {
        getProjects(); //Your firebase call to get projects
      }
    }, []);

    const getProjects = async () => {
      //call firebase and get the projects
      setProjects(projects)
    }

    return projects ? (
    <div className="App">
            <Router history={history}>
                <ScrollToTop>
                    <Header/>
                    <Route path="/project/:name" component={Project}/>
                    <Route path="/about" component={About}/>
                    <div className="hs">
                        <Route path={["/", "/project/:name"]} exact component={() => <CartHolder projects={projects}/>}/>
                    </div>
                    <div className="hs-mobile">
                        <Route path="/" exact component={CartHolderMobile}/>
                    </div>
                </ScrollToTop>
            </Router>
        </div>
    ) : (
    <BlackScreen />
    )
}
GRS
  • 1,829
  • 1
  • 9
  • 23
0

Your component needs to return something in the render method so display your app conditionally. Something like:

function App() {

    const projects = firebase.firestore().collection('projects').onSnapshot(snap => {
        let projects = [];
        snap.forEach(doc => {
            projects.push(doc.data())
        });
        return projects;
    })
render() {
    {!projects && return <BlackScreen />}
        {projects && 
            <div className="App">
                <Router history={history}>
                    <ScrollToTop>
                        <Header/>
                        <Route path="/project/:name" component={Project}/>
                        <Route path="/about" component={About}/>
                        <div className="hs">
                            <Route path={["/", "/project/:name"]} exact component={() => <CartHolder projects={projects}/>}/>
                        </div>
                        <div className="hs-mobile">
                            <Route path="/" exact component={CartHolderMobile}/>
                        </div>
                    </ScrollToTop>
                </Router>
            </div>
        );
    });
  }
}
Luke
  • 537
  • 4
  • 10