I want to render the home component according to the data passed into currentUser state. But as getCurrentUser() function is asynchronous, all the react components renders before the data is fetched and stored into currentUser state. As the useEffect() only runs once just after signup hence despite of having data stored into currentUser state the components did not get data initially. But if I reload the app then the data starts to appear. I want either components render after all the data fetching is done or Components re-renders once the data is fetched successfully.
This is app.js file
import './App.css';
import {
Routes,
Route,
} from "react-router-dom";
import Signup from './components/Signup';
import Signin from './components/Signin';
import Home from './components/Home';
import About from './components/About';
import Layout from './components/Layout';
import Labs from './components/Labs';
import Contact from './components/Contact';
import Forum from './components/Forum';
function App() {
return (
<Routes>
<Route exact path="/" element={<Layout />}>
<Route index element={<Home />} />
<Route path="about" element={<About />} />
<Route path="labs" element={<Labs />} />
<Route path="forum" element={<Forum />} />
<Route path="contact" element={<Contact />} />
<Route path="signup" element={<Signup />} />
<Route path="signin" element={<Signin />} />
</Route>
</Routes>
);
}
export default App;
This is Layout.js file where data fetching is done
import React, { useEffect, useState } from 'react';
import { Outlet } from "react-router-dom";
import Navbar from './Navbar';
function Layout() {
const [currentUser, setCurrentUser] = useState({
name: "",
email: "",
signedIn: false,
admin: false
})
const getCurrentUser = async () => {
try {
const res = await fetch('/userinfo', {
method: "GET",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
credentials: "include"
});
const data = await res.json()
if (res.status !== 200 || !data) {
const error = new Error(res.error);
throw error;
} else {
const { name, email, admin } = data.userInfo;
setCurrentUser({name, email, admin, signedIn: true})
}
} catch (err) {
console.log(err.message);
}
};
useEffect(() => {
getCurrentUser();
}, []);
const setUserInfo = (data) => {
setCurrentUser(data);
}
console.log('layout', currentUser)
return (
<div>
<Navbar signedInfo={currentUser} setSignedInfo={setUserInfo} />
<div>
<Outlet context={[currentUser, setUserInfo]} />
</div>
</div>
)
}
export default Layout. I have user useOutletContext() hook to pass state data to outlet components
This is the code for one of the component i.e. Home.js. I am providing this to give an idea that as soon as I signin into the app it fetches data from server and the name it fetched is displayed into this component. But as soon as I sign In the name is not displayed on home page. But then when I refresh the page the name starts to appear.
import React from 'react'
import { useNavigate, useOutletContext } from 'react-router-dom'
function Home() {
const navigate = useNavigate();
const [currentUser, setUserInfo] = useOutletContext();
const redirectTo = () => {
if(currentUser.signedIn) {
navigate('/labs');
} else {
navigate('/signin')
}
}
return (
<div className='flex flex-col items-center space-y-10 animate-fadeIn'>
<h1 className="text-3xl pt-32 text-center font-semibold font-sans md:text-4xl lg:text-5xl">Welcome <span className='text-blue-500'>{ currentUser.name }</span><br /> To Control System Engineering Labs</h1>
<p className='text-center mx-5 md:max-w-3xl'>Control systems are everywhere, from the tiniest dial functioning inside your watch to the gigantic satellite revolving around the planet. They constantly synchronise the behaviour of devices in a recurrent and predicted way.</p>
<button onClick={redirectTo} className="inline-block px-4 py-2 text-white bg-blue-600 rounded-md shadow hover:bg-blue-700 focus:bg-blue-700 focus-outline:none active:bg-blue-800 transition duration-150 ease-in-out">Get Started</button>
</div>
)
}
export default Home