I have an App component under which I have got three more component Login,Register,DashBoard and under the DashBoard component I have NavBar which has children as Content
Here is App.js
const App = () => {
return (
<div className="app">
<Router>
<Switch>
<Route exact path="/" element={<Login />} />
<Route exact path="/register" element={<Register />} />
<Route exact path="/dashboard" element={<Dashboard />} />
</Switch>
</Router>
</div>
);
};
In Login.js component when a user login is successful then I'm storing the email and displayName into a user object in localStorage of the browser
Here is DashBoard.js
const Dashboard = () => {
const { displayName, email } = JSON.parse(localStorage.getItem("user"));
return (
<NavBar displayName={displayName}>
<Content></Content>
</NavBar>
);
};
Register.js
const Register = () => {
const [register, setRegister] = useState({
name: "",
phoneNumber: "",
email: "",
password: "",
});
const navigate = useNavigate();
const { name, phoneNumber, email, password } = register;
const [user] = useAuthState(auth);
const handleChange = (name) => (e) => {
e.preventDefault();
setRegister({ ...register, [name]: e.target.value });
};
useEffect(() => {
if (loading) return;
console.log(user);
if (user) navigate("/dashboard", { replace: true });
}, [user]);
return (
<div style={{ marginTop: "15rem" }}>
<Container>
<Row className="justify-content-lg-center">
<Col xs>
<FloatingLabel
controlId="floatingInput"
label="Name"
className="mb-3"
>
<Form.Control
type="text"
placeholder="Doe joe"
value={name}
onChange={handleChange("name")}
/>
</FloatingLabel>
<FloatingLabel
controlId="floatingPassword"
label="Phone Number"
className="mb-3"
>
<Form.Control
type="number"
placeholder="phoneNumber"
value={phoneNumber}
onChange={handleChange("phoneNumber")}
name="email"
/>
</FloatingLabel>
<FloatingLabel
controlId="floatingInput"
label="Email Address"
className="mb-3"
>
<Form.Control
type="email"
placeholder="Enter your Email.."
value={email}
onChange={handleChange("email")}
name="email"
/>
</FloatingLabel>
<FloatingLabel
controlId="floatingPassword"
label="Password"
className="mb-3"
>
<Form.Control
type="password"
placeholder="Password"
value={password}
onChange={handleChange("password")}
name="phoneNumber"
/>
</FloatingLabel>
<Button
variant="primary"
onClick={() => {
registerWithEmailAndPassword(
name,
phoneNumber,
email,
password
);
navigate("/");
}}
>
Register
</Button>
</Col>
</Row>
</Container>
</div>
);
};
Here Firebase.js
const firebaseConfig = {
//firebase config
};
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
//signIn Using google
const logInWithEmailAndPassword = async (email, password) => {
try {
const res = await signInWithEmailAndPassword(auth, email, password);
const user = res.user;
} catch (err) {
console.log(err);
return err;
}
};
const registerWithEmailAndPassword = async (
name,
phoneNumber,
email,
password
) => {
try {
const res = await createUserWithEmailAndPassword(
auth,
email,
password,
name,
phoneNumber
);
const user = res.user;
await updateProfile(auth.currentUser, {
displayName: name,
});
await addDoc(collection(db, "users"), {
uid: user.uid,
name: name,
phoneNumber: phoneNumber,
authProvider: "local",
email,
password,
});
} catch (err) {
console.error(err);
}
};
//logout
//exporting
NavBar.js
const NavBar = (props) => {
const [user] = useAuthState(auth); //react-firebase-hook/auth
const navigate = useNavigate();
const handleLogout = () => {
logout();
};
useEffect(() => {
if (!user) navigate("/");
}, [user]);
return (
<>
<Navbar bg="light" variant="light">
<Container>
<Navbar.Brand href="/dashboard">React-Bootstrap</Navbar.Brand>
<Navbar.Toggle aria-controls="responsive-navbar-nav" />
<Navbar.Collapse id="responsive-navbar-nav">
<Nav className="me-auto"></Nav>
<Nav>
<Button variant="danger" onClick={handleLogout}>
Logout
</Button>
<Nav.Link href="#deets"></Nav.Link>
{user && (
<Navbar.Text>Signed in as: {props.displayName}</Navbar.Text>
)}
</Nav>
</Navbar.Collapse>
</Container>
</Navbar>
{props.children}
</>
);
};
I'm displaying the name of the user in the Navbar component but after registering when the user is navigated to the root route which is login component which has an effect attached to it if the user then navigates to dashboard where the Navbar component will show the displayName but it is coming as null when I reload the page then it is showing the name. How can I show the displayName on initial render after registering when user is redirected to DashBoard
CodePudding user response:
You haven't included the NavBar component which you having issues with. It seems like a race condition in which the props are passed to NavBar before the values are set / retrieved. Perhaps try something like this in your NavBar component:
import { useEffect, useState } from 'react'
const NavBar = () => {
const [displayName, setDisplayName] = useState('')
const [email, setEmail] = useState('')
// get the values when the component is rendered
useEffect(() => {
const { displayName, email } = JSON.parse(localStorage.getItem("user"));
setDisplayName(displayName)
setEmail(email)
}, [])
return (
<NavBar>
<span>Email: {email}</span>
<span>Display Name: {displayName}</span>
</NavBar>
);
};
CodePudding user response:
I kind of got a Solution to this, from the top of the component tree at App.js Added these lines
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [user] = useAuthState(auth);
useEffect(() => {
setTimeout(() => {
if (user !== null) {
setName(user.displayName);
setEmail(user.email);
}
}, 1000);
}, [user]);
And then went on drilling down the props to the required component. Not a dependable solution but it is working for me right now