I am using react-router to create 2 pages. The first page is a login page. If the user clicks the google Sign up button created through npm module called google-button
, then they get signed into their account and navigated to account route.
I am trying to pass a name through the context hook but am unable to view the name in account page.
I am re-routed to the account page but receive no value for name. This is what I am getting in the console of account page --->
Context value in Account: undefined
I am really stuck and have no idea what to do.
index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
import App from "./App";
import Account from "./components/Account";
const router = createBrowserRouter([
{
path: "/",
element: <App />
},
{
path: "/account",
element: <Account />
}
]);
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<RouterProvider router={router} />
);
App.js
import React, { useState, useEffect, createContext } from 'react';
import GoogleButton from 'react-google-button';
import { Navigate } from 'react-router';
export const UserNameContext = createContext();
const App = () => {
const [user, setUser] = useState(false);
const name = "Lea";
const handleClick = () => {
setUser(!user);
};
useEffect(() => {
console.log("user value changed");
}, [user]);
return (
<UserNameContext.Provider value={name}>
<div>
<h1>Sign In</h1>
<GoogleButton onClick={handleClick} />
{user ? <Navigate to="/account" /> : "User is Signed Out"}
</div>
</UserNameContext.Provider>
);
}
export default App;
Account.js file -
import React, { useContext } from 'react';
import { UserNameContext } from "../App.js";
const Account = () => {
const name = useContext(UserNameContext);
console.log("Context value in Account:", name);
return (
<div>
<h1>Account page</h1>
<p>{name}</p>
</div>
);
}
export default Account;
If you would like the UserNameContext
context value to be accessible outside the App
component's sub-ReactTree then UserNameContext.Provider
needs to be rendered higher in the ReactTree.
Suggestion is to move the state and UserNameContext.Provider
to the index file and provide the context to the sub-ReactTree rendering the routes and routed components, e.g. App
and Account
.
Create a provider component to hold and provide the context value:
UserNameProvider
import React, {
useContext,
useState,
useEffect,
createContext
} from 'react';
export const UserNameContext = createContext();
export useUserNameContext = () => useContext(UserNameContext);
const UserNameProvider = ({ children }) => {
const [user, setUser] = useState(false);
const name = "Lea";
const handleClick = () => {
setUser(!user);
};
useEffect(() => {
console.log("user value changed");
}, [user]);
return (
<UserNameContext.Provider value={{ name, user, handleClick }}>
{children}
</UserNameContext.Provider>
);
}
export default UserNameProvider;
App
import React from 'react';
import GoogleButton from 'react-google-button';
import { Navigate } from 'react-router';
import { useUserNameContext } from '../path/to/UserNameProvider';
const App = () => {
const { user, handleClick } = useUserNameContext();
return (
<div>
<h1>Sign In</h1>
<GoogleButton onClick={handleClick} />
{user ? <Navigate to="/account" /> : "User is Signed Out"}
</div>
);
}
export default App;
index.js
Create a layout route component to render the UserNameProvider
component and an Outlet
for nested routes to render their content into.
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import {
createBrowserRouter,
RouterProvider,
Outlet
} from 'react-router-dom';
import UserNameProvider from '../path/to/UserNameProvider';
import App from "./App";
import Account from "./components/Account";
const UserNameProviderLayout = () => (
<UserNameProvider>
<Outlet />
</UserNameProvider>
);
const router = createBrowserRouter([
{
element: <UserNameProviderLayout />,
children: [
{
path: "/",
element: <App />
},
{
path: "/account",
element: <Account />
}
],
},
]);
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<RouterProvider router={router} />
);
Account
import React from 'react';
import { useUserNameContext } from '../path/to/UserNameProvider';
const Account = () => {
const { name } = useUserNameContext();
console.log("Context value in Account:", name);
return (
<div>
<h1>Account page</h1>
<p>{name}</p>
</div>
);
}
export default Account;