Cannot read property 'isLoggedIn' of null - reactjs

Hi all I am currently stuck with the following:
Cannot read property 'isLoggedIn' of null
> 9 | const Header = () => {
10 | const {isLoggedIn} = useContext(AuthContext);
11 | return (
12 | <ul className="nav">
I am new in React and I was following a tutorial to implement a sign-in/sign-up form and sending data to firebase (which is also something completely new to me). I was able to fix a couple of previous issues on my own but I am now stuck at this one.
If I don't import the Header into the Routing the site works fine but as soon as I try to import it in any way to Routing.js it's failing.
Header.js
import React, { useContext } from "react";
import routes from "./routes";
import { Link } from "react-router-dom";
import { AuthContext } from "./test";
const Header = () => {
const {isLoggedIn} = useContext(AuthContext);
return (
<ul className="nav">
{routes.map((route, i) => (
<li key={i}>
<Link to={route.path}>{route.name}</Link>
</li>
))}
{isLoggedIn && <li><Link to="/reports">Profile</Link></li>}
</ul>
)
}
export default Header;
Routing.js
import React from "react";
import Head from "./Head";
import Join from "./Join";
import Login from "./Login";
import Test from "./test";
import HomePage from "./HomePage";
import Header from "./Header";
import { BrowserRouter as Router, Switch, Route, Link} from "react-router-dom";
function Home() {
return (
<div className="App">
<Head />
<HomePage />
</div>
);
}
function Reviews() {
return (
<div className="App">
<Head />
</div>
);
}
function Logging() {
return (
<div className="App">
<Head />
<Header />
<Test />
</div>
);
}
function Signup() {
return (
<div className="App">
<Head />
<Header />
<Test />
</div>
);
}
function App() {
return (
<Router>
<Switch>
<Route path="/" exact component={Home} />
<Route path="/review" exact component={Reviews} />
<Route path="/login" exact component={Logging} />
<Route path="/signup" exact component={Signup} />
</Switch>
</Router>
)
}
export default App;
import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
import { Switch, BrowserRouter as Router, Route } from "react-router-dom";
import routes from "./routes.js";
import Header from "./Header";
import "./styles.css";
import * as firebase from "firebase";
import firebaseConfig from "./firebase.config";
import protectedRoutes from './protectedRoutes'
import ProtectedRouteHoc from './ProtectedRouteHoc'
firebase.initializeApp(firebaseConfig);
export const AuthContext = React.createContext(null);
function Test() {
const [isLoggedIn, setLoggedIn] = useState(false);
function readSession() {
const user = window.sessionStorage.getItem(
`firebase:authUser:${firebaseConfig.apiKey}:[DEFAULT]`
);
if (user) setLoggedIn(true)
}
useEffect(() => {
readSession()
}, [])
return (
<AuthContext.Provider value={{ isLoggedIn, setLoggedIn }}>
Is logged in? {JSON.stringify(isLoggedIn)}
<div className="App">
<Router>
<Header isLoggedIn={isLoggedIn}/>
<Switch>
{protectedRoutes.map(route => (
<ProtectedRouteHoc
key={route.path}
isLoggedIn={isLoggedIn}
path={route.path}
component={route.main}
exact={route.exact}
public={route.public}
/>
))}
{routes.map(route => (
<Route
key={route.path}
path={route.path}
exact={route.exact}
component={route.main}
/>
))}
</Switch>
</Router>
</div>
</AuthContext.Provider>
);
}
export default Test;
I would appreciate any tips or things I can read through to get a better understanding in this.

You're destructing the return value of useContext(AuthContext). You're expecting it to return an object with a key isLoggedIn, e.g. { isLoggedIn: false }, but it's returning null instead. You probably haven't given it a default value when you instantiated the context instance, e.g.
// Possibly what you're doing, no default value
const AuthContext = React.createContext() // null
// Instantiated with a default value
const AuthContext = React.createContext({ isLoggedIn: false })

Related

I am calling a prop 2 times but it is working first time not working seond time

import React, { useEffect, useState } from 'react'
import { Link } from 'react-router-dom';
import './Allproducts.css'
import Categories from './categories.json'
import ForYouItem from './ForYouItem'
export default function Allproducts(props) {
const [products, setProducts] = useState([]);
useEffect(() => {
fetch(`https://fakestoreapi.com/products/category/${props.category}`)
.then((res) => res.json())
.then((data) => setProducts(data))
}, [])
return (
<>
<div className="banner">
<h1>All Products</h1>
<h4>Get best items in budget</h4>
</div>
<div className="main-grid">
<div className="left-grid">
<div className="left-categories">
<h1>Collections</h1>
{Categories.map((category) => {
let Afeef = `/${props.category}`
return (
<Link to= {Afeef} className='products-categories'> <h4>{category.title}</h4></Link>
)
}
)}
</div>
</div>
<div className="right-grid">
<div className="row ">
{products.map((product) => {
return (
<div className="col-md-4 my-2 Products-1">
<ForYouItem Title={product.title.slice(0, 50)} Price={product.price} Imageurl={product.image} rate={product.rating.rate} count={product.rating.count} />
</div>
)
}
)}
</div>
</div>
</div>
</>
)
}
So in this code I am calling same prop two times, first in this line;
fetch(https://fakestoreapi.com/products/category/${props.category})
Secondly here;
let Afeef = /${props.category}
The prop is working in the First line but on the second line it gives no result. The link isn't changed.
What I want is when I click on second Link I get redirected "/${props.category}" but the URL is not changing
Code for App.js:
import React, { Component } from 'react'
import './App.css';
import NavBar from './components/NavBar';
import TopBar from './components/TopBar'
import {
HashRouter,
Routes,
Route,
} from "react-router-dom";
import Mainpage from './Mainpage';
import Login from './components/Login';
import Signup from './components/Signup';
import Allproducts from './components/Allproducts';
function App() {
return (
<div>
<HashRouter>
<TopBar/>
<NavBar/>
<Routes>
<Route path="/" element={<Mainpage/>}></Route>
<Route path="/Login" element={<Login/>}></Route>
<Route path="/Signup" element={<Signup/>}></Route>
<Route path="/jewelery" element={<Allproducts category="jewelery"/>}></Route>
<Route path="/electronics" element={<Allproducts category="electronics"/>}></Route>
<Route path="/men's clothing" element={<Allproducts category="men's clothing"/>}></Route>
<Route path="/women's clothing" element={<Allproducts category="women's clothing"/>}></Route>
</Routes>
</HashRouter>
</div>
);
}
export default App;

React fullpageJS and react-router-dom

I am trying to use react fullpageJS and react router dom to create a carousel but it shows empty screen, Here's the code I am using:
APP.JS:
import { Route, Routes } from "react-router-dom";
import Navigation from "./routes/navigation/navigation.component";
import Home from "./components/home/home.component";
function App() {
const About = () => {
return (
<div>
<h1>This is about</h1>
</div>
);
};
return (
<div>
<Routes>
<Route path="/" element={<Navigation />}>
<Route index element={<Home />} />
<Route path="/about" element={<About />} />
</Route>
</Routes>
</div>
);
}
export default App;
Home.jsx:
import { useState, useEffect, React } from "react";
import ProjectPreview from "../project-preview/project-preview.component";
import ReactFullpage from "#fullpage/react-fullpage";
// import "fullpage.js/vendors/scrolloverflow";
import PROJECTS_DATA from "../../Projects";
const Home = () => {
const [projectsToPreview, setProjects] = useState([]);
useEffect(() => {
setProjects(PROJECTS_DATA);
}, []);
<ReactFullpage
render={() => {
return (
<ReactFullpage.Wrapper>
<ReactFullpage.Wrapper>
{projectsToPreview.map((project) => {
return (
<div className="section" key={project.id}>
<h1>Test</h1>
<ProjectPreview project={project} />
</div>
);
})}
</ReactFullpage.Wrapper>
</ReactFullpage.Wrapper>
);
}}
/>;
};
export default Home;
The rendered screen shows only the navbar component but the content in the slider appear neither on the screen nor in the javascript dom
index.js:
import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
);
reportWebVitals();
Navigation.jsx
import { Link, Outlet } from "react-router-dom";
import { Nav, Navbar } from "react-bootstrap";
const Navigation = () => {
return (
<>
<Navbar expand="lg" variant="dark">
<Link className="navbar-brand" to="/">
LOGO
</Link>
<Nav className="ms-auto">
<Link className="nav-link" to="/about">
About
</Link>
</Nav>
</Navbar>
<Outlet />
</>
);
};
export default Navigation;
I suspect the issue is that the Navigation component isn't rendering an Outlet component for the nested routes to render their element into.
Navigation should render an Outlet.
Example:
import { Outlet } from 'react-router-dom';
const Navigation = () => {
...
return (
... nav and layout UI
<Outlet /> // <-- nested routes render content here
...
);
};

Props Passing 2 objects when only 1 is needed, React

So I am trying only to pass one value, but it has currently two values here. It's passing the selected hive, and an additional array. I tried removing props but then it won't pass anything. I tried adding another hook for it but I may be doing it incorrectly. Any assistance is greatly appreciated!
App.js
// General Imports
import { Routes, Route } from "react-router-dom";
import "./App.css";
// Pages Imports
import HomePage from "./pages/HomePage/HomePage";
import LoginPage from "./pages/LoginPage/LoginPage";
import RegisterPage from "./pages/RegisterPage/RegisterPage";
import AddHivePage from "./pages/AddHive/AddHive";
import UpdateHivePage from "./pages/UpdateHivePage/UpdateHivePage";
import InspectionPage from "./pages/InspectionPage/InspectionPage";
// Component Imports
import Navbar from "./components/NavBar/NavBar";
import Footer from "./components/Footer/Footer";
// Util Imports
import PrivateRoute from "./utils/PrivateRoute";
import { useState } from "react";
function App() {
const [selectedHive, setSelectedHive] = useState('')
return (
<div>
<Navbar />
<Routes>
<Route
path="/"
element={
<PrivateRoute>
<HomePage setSelectedHive={setSelectedHive} />
</PrivateRoute>
}
/>
<Route path="/register" element={<RegisterPage />} />
<Route path="/login" element={<LoginPage />} />
<Route path="/addhive" element={<PrivateRoute><AddHivePage /></PrivateRoute>}/>
<Route path="/hives/update/:id" element={<PrivateRoute><UpdateHivePage selectedHive={selectedHive} /></PrivateRoute>}/>
<Route path="/inspections/all/:id" element={<PrivateRoute><InspectionPage selectedHive={selectedHive} /></PrivateRoute>}/>
</Routes>
<Footer />
</div>
);
}
Homepage
import React from "react";
import { Link } from "react-router-dom";
import Hive from "../../components/Hive/Hive";
const HomePage = (props) => {
return (
<div className="container">
<Hive setSelectedHive={props.setSelectedHive} />
<Link to="/addhive">Add Hive!</Link>
</div>
);
};
export default HomePage;
Inspection component
import React, { useState, useEffect } from 'react';
import DisplayInspections from '../DisplayInspections/DisplayInspections';
import useAuth from '../../hooks/useAuth';
import axios from 'axios';
const Inspections= (selectedHive, props) => {
const [user, token] = useAuth();
const [inspections, setInspections] = useState([]);
useEffect(()=>{
fetchInspections(props.setSelectedValue);
}, [])
const fetchInspections = async () => {
try {console.log(selectedHive)
let response = await axios.get(`http://127.0.0.1:8000/api/inspections/all/${selectedHive}`, {
headers: {
Authorization: "Bearer " + token,
},
});
setInspections(response.data);
} catch (error) {
console.log(error.response.data);
}
};
return (
<div className="container">
<h1>List of Inspections</h1>
<DisplayInspections inspections={inspections} setSelectedHive={props.setSelectedHive} />
</div>
);
}
export default Inspections;
This is where I am trying to send the data from for my axios call.
Display.jsx
import React from "react";
import { useNavigate } from "react-router-dom";
const DisplayHives = ({hives, setSelectedHive}) => {
const navigate = useNavigate()
function handleClick(id){
setSelectedHive(id);
navigate(`/hives/update/${id}`)
}
function handleClickInspection(id){
setSelectedHive(id);
navigate(`/inspections/all/${id}`)
}
return (
<>
<table>
<tbody>
{hives.map((hive)=> {
return(
<tr key={hive.id} >
<td>{hive.hive_number}</td>
<td>{hive.inspection_date} </td>
<td> <button onClick={() => handleClickInspection(hive.id)}>Inspections</button></td>
<td>
<button onClick={() => handleClick(hive.id)}>Update</button>
</td>
</tr>
)
})}
</tbody>
</table>
</>
);
}
export default DisplayHives;

Best practise: Where to put the Navbar component so that it -re-renders with every page?

This has been bugging me for a long time, and my head just can't seem to come up with a solution that works fluently. I will try to be short:
I have a React app where I update my Navbar based on an access token being stored as a cookie or not (user authenticated or not). But in order for my Navbar to update whether the user is authenticated, I have to refresh the page. I believe it is because my Navbar is being rendered way up (in?) the component tree, and does not get re-rendered whenever I visit a new page (only when I refresh).
What is the best way to render my Navbar component so that every page shares the same component, BUT the Navbar re-renders on every new page visited? Or is this even a wise thing to do?
Let me know if I am not explaining myself clearly.
index.jsx
import React from "react";
import ReactDOM from "react-dom";
import { App } from "./components/App";
import { BrowserRouter } from "react-router-dom";
import "./styles/styles.css";
import { PublicClientApplication } from "#azure/msal-browser";
import { MsalProvider } from "#azure/msal-react";
import { msalConfig } from "./lib/authConfig";
const msalInstance = new PublicClientApplication(msalConfig);
ReactDOM.render(
<MsalProvider instance={msalInstance}>
<BrowserRouter>
<App />
</BrowserRouter>
</MsalProvider>,
document.getElementById("root")
);
App.jsx
import React from "react";
import { Router } from "./Router";
import { Navbar } from "./Navbar";
export function App() {
return (
<div>
<Navbar />
<Router />
</div>
);
}
Router.jsx
import { Route } from "react-router-dom";
import React from "react";
import { MainPage } from "./MainPage";
import { LoginPage } from "./LoginPage";
import { GoogleLogin } from "./GoogleLogin";
import { GoogleLoginCallback } from "./GoogleLoginCallback";
import { GoogleLogout } from "./GoogleLogout";
import { NewArticle } from "./NewArticle";
export function Router() {
return (
<div>
<Route exact path="/" component={MainPage} />
<Route exact path="/login" component={LoginPage} />
<Route exact path="/login/google" component={GoogleLogin} />
<Route exact path="/logout/google" component={GoogleLogout} />
<Route exact path="/newArticle" component={NewArticle} />
<Route
exact
path="/login/google/callback"
component={GoogleLoginCallback}
/>
</div>
);
}
Navbar.jsx
import React, { useEffect, useState } from "react";
import { NavLink } from "react-router-dom";
import { useIsAuthenticated, useMsal } from "#azure/msal-react";
import { fetchJSON } from "../lib/fetchJSON";
export function Navbar() {
const activeStyle = {
borderBottom: "10px solid white",
};
const [username, setUsername] = useState();
const { accounts } = useMsal();
const name = accounts[0] && accounts[0].name;
const hasCookie = document.cookie.startsWith("access_token");
const isAuthenticated = useIsAuthenticated();
useEffect(async () => {
const res = await fetchJSON("/api/login/google");
if (hasCookie) {
setUsername(res.userinfo.given_name);
}
}, []);
return (
<>
<div className={"navbar-container"}>
<NavLink exact to="/" activeStyle={activeStyle}>
Home
</NavLink>
<NavLink exact to="/login" activeStyle={activeStyle}>
Login-portal
</NavLink>
{isAuthenticated ? (
<NavLink exact to="/newArticle" activeStyle={activeStyle}>
New Article
</NavLink>
) : (
<div />
)}
{isAuthenticated || hasCookie ? (
<p className="logged-in">
Logged in as {username} {name}
</p>
) : (
<p className="logged-in">Not logged in</p>
)}
</div>
</>
);
}

Wrapper Component showing different navigation on different pages

I'm trying to make my page flexible to show different navigation bars depending on the page I'm on. When I run the page with the code presented below it shows the different navs as they should, but the actualRouteComponent is not showing the content of the route component eg. FrontpageRoute, BookRoute.
This is my App.js:
import React from 'react';
import {BrowserRouter as Router, Switch} from 'react-router-dom';
import './Mystyles.scss';
//Routes
import DynamicLayout from './layout/DynamicLayout'
import FrontpageRoute from './routes/FrontpageRoute';
import BookRoute from './routes/BookRoute';
function App() {
return (
<Router>
<div className="App">
<Switch>
<DynamicLayout
exact
path="/"
component={FrontpageRoute}
/>
<DynamicLayout
exact
path="/book"
component={BookRoute}
layout="SUB_NAV"
/>
</Switch>
</div>
</Router>
);
}
export default App;
This is my DynamicLayoutRoute.js:
import React from 'react';
import {BrowserRouter as Route} from 'react-router-dom';
import Header from './../components/Header';
import MainNavigation from '../components/MainNavigation';
const DynamicLayout = props => {
const { component: RoutedComponent, layout, ...rest } = props;
const actualRouteComponent = (
<Route
{...rest}
render={props => (
<RoutedComponent {...props} />
)}
/>
);
switch (layout) {
case 'MAIN_NAV': {
return (
<div>
<MainNavigation />
<Header />
{actualRouteComponent}
</div>
)
}
case 'SUB_NAV': {
return (
<div>
<MainNavigation />
<h2>Sub Nav</h2>
<Header />
{actualRouteComponent}
</div>
)
}
default: {
return (
<div>
<MainNavigation />
<Header />
{actualRouteComponent}
</div>
)
}
}
};
export default DynamicLayout;
and here is my MainNavigation.js:
import React, { Component } from 'react'
import { NavLink } from 'react-router-dom'
class MainNavigation extends Component {
render() {
return (
<nav className="main-navigation">
<div className="main-navigation--content">
<div className="mobil-nav">
<span>Burger</span>
</div>
<div className="link-list">
<NavLink exact to="/">Frontpage</NavLink>
<NavLink exact to="/book">Book</NavLink>
</div>
<div className="social">
<span>Instagram</span>
</div>
</div>
</nav>
)
}
}
export default MainNavigation
Can someone tell me what is wrong?
I see that in your DynamicLayoutRoute component you are accessing props as this.props. this is undefined in functional components.
Access props like this -
const DynamicLayoutRoute = props => {
const { component: RoutedComponent, layout, ...rest } = props;
...
}

Resources