Why useContext return undefined? - javascript

I have an issue that is useContext return undefined value.
I create a context for collapsing menu like toggle menu. Afterward I added provider into index file to wrap Main component. I go to Main file import CollapseContext but this is file it's not work :( ?
I don't understand why it return undefined.
Below is my code.
src/context/CollapseMenuContext.js
import React, { createContext, useState } from 'react'
export const CollapseContext = createContext()
export default function CollapseProvider({ children }) {
const [isCollapse, setIsCollapse] = useState(false)
const toggleCollapse = () => {
setIsCollapse(!isCollapse)
}
const values = {
isCollapse,
toggleCollapse,
}
return <CollapseContext.Provider value={values}>{children}</CollapseContext.Provider>
}
src/app/index.jsx
import React from 'react'
import Header from '_components/Header'
import CollapseProvider from '../context/CollapseMenuContext.js'
import MainDigistallDesktop from './Main'
function DigistallDesktop() {
return (
<CollapseProvider>
<Header />
<section className='section-content section-content--top mains-screen pb-0' id='checkHeight'>
<MainDigistallDesktop />
</section>
</CollapseProvider>
)
}
export default DigistallDesktop
src/app/Main.jsx
import React, { useContext } from 'react'
import { Route, Switch } from 'react-router-dom'
import OrderRecord from './OrderRecord'
import Sidebar from './components/Sidebar/index'
import Dashboard from './Dashboard'
import Delivery from './Delivery'
import Products from './Products'
import Setting from './Setting'
import { CollapseContext } from '../context/CollapseMenuContext.js'
function MainDigistallDesktop() {
const context = useContext(CollapseContext)
console.info(context)
return (
<div className='container-fluid' style={{ minWidth: '1200px' }}>
<div className='row'>
{/* <div className={`${isCollapse ? 'col-1' : 'col-2'} position-relative`}>
<Sidebar />
</div> */}
<div className='col-10 mx-auto'>
<Switch>
<Route path='/' exact component={Dashboard} />
<Route path='/order-records' exact component={OrderRecord} />
<Route path='/delivery' exact component={Delivery} />
<Route path='/products' exact component={Products} />
<Route path='/setting' exact component={Setting} />
</Switch>
</div>
</div>
</div>
)
}
export default MainDigistallDesktop
result:
Eidt 1:
This is root app file:
export default function App() {
if (process.env.REACT_APP_ENVIRONMENT === 'production') useScript()
return (
<Provider store={store}>
<ToastProvider>
<FirebaseContext.Provider value={{ firebase }}>
<Router history={history}>
<Switch>
<Route path='/sign-in' exact={true} component={SignInPage} />
<Route path='/sign-up' exact={true} component={SignUpPage} />
<Route path='/reset-password' exact={true} component={ForgotPasswordPage} />
<Route path='/reset-password-with-code' component={ResetPasswordPage} />
<Route path='/info' exact={true} component={RedirectGoogleSites} />
<Route path='/policy' exact={true} component={Policy} />
<ProtectedRoute path='/welcome' exact={true} component={Welcome} />
<ProtectedRoute path='/digistall' component={Digistall} /> --> this is index.jsx file
{/* <ProtectedRoute path='/' component={MainPage} /> */}
<ProtectedRoute path='/' component={MainDigistallDesktop} /> --> lead to my app current (Main.jsx)
</Switch>
</Router>
</FirebaseContext.Provider>
</ToastProvider>
</Provider>
)
}

EDIT: You need to wrap CollapseProvider with MainDigistallDesktop. in your app component:
return (
<Provider store={store}>
<ToastProvider>
<FirebaseContext.Provider value={{ firebase }}>
<Router history={history}>
<Switch>
<Route path='/sign-in' exact={true} component={SignInPage} />
<Route path='/sign-up' exact={true} component={SignUpPage} />
<Route path='/reset-password' exact={true} component={ForgotPasswordPage} />
<Route path='/reset-password-with-code' component={ResetPasswordPage} />
<Route path='/info' exact={true} component={RedirectGoogleSites} />
<Route path='/policy' exact={true} component={Policy} />
<ProtectedRoute path='/welcome' exact={true} component={Welcome} />
<ProtectedRoute path='/digistall' component={Digistall} /> --> this is index.jsx file
{/* <ProtectedRoute path='/' component={MainPage} /> */}
<ProtectedRoute path='/' render={() => (
<CollapseProvider>
<MainDigistallDesktop/>
</CollapseProvider>
)} /> --> lead to my app current (Main.jsx)
</Switch>
</Router>
</FirebaseContext.Provider>
</ToastProvider>
</Provider>
)

Related

How do I redirect from a root path to another root path and still render sub-routes?

import React from 'react';
import { BrowserRouter as Router, Route, Switch, Redirect } from 'react-router-dom';
import Footer from './components/Footer';
import NavMenu from './components/NavMenu';
import ScrollToTop from './components/ScrollToTop';
import About from './pages/About';
import Contact from './pages/Contact';
import Home from './pages/Home';
import Projects from './pages/Projects';
import Gallery from './pages/Gallery';
export default function App() {
return (
<>
<Router>
<NavMenu />
<ScrollToTop />
<Switch>
<Route path="/about">
<About />
</Route>
<Route path="/contact">
<Contact />
</Route>
<Route path="/projects">
<Projects />
</Route>
<Route path="/gallery/">
<Redirect to="/projects" />
<Gallery />
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
<Footer />
</Router>
</>
);
}
The problem is that I want it to redirect (example.com/gallery) to (example.com/projects)
but let me use something like (example.com/gallery/photo1) without redirect as well to (example.com/projects)
Render two separate routes, one to redirect from "/gallery" to "/projects", and the other for a specific gallery.
Example:
export default function App() {
return (
<>
<Router>
<NavMenu />
<ScrollToTop />
<Switch>
<Route path="/about">
<About />
</Route>
<Route path="/contact">
<Contact />
</Route>
<Route path="/projects">
<Projects />
</Route>
<Route path="/gallery/:galleryId">
<Gallery />
</Route>
<Redirect from="/gallery" to="/projects" />
<Route path="/">
<Home />
</Route>
</Switch>
<Footer />
</Router>
</>
);
}
You can use the exact prop to specify an exact route, meaning sub-routes will not be matched.
<Route exact path="/gallery/">
<Redirect to="/projects" />
<Gallery />
</Route>

Uncaught Error: [ItemListContainer] is not a <Route> component. All component children of <Routes> must be a <Route> or <React.Fragment>

I'm programming in react, the truth is the first time that I program it in React.
in App.js I define the routes, I use the react-router-dom library, but I get the error of the title, the code is the following, what am I doing wrong, can you explain it to me, because I bring all the components.
import React from 'react';
import './App.css';
import 'materialize-css/dist/css/materialize.css';
import NavBar from './components/NavBar';
import ItemListContainer from './components/ItemListContainer';
import MoreSell from './components/ItemListMoreSell';
import ItemDetailContainer from './components/ItemDetailContainer';
import Cart from './components/Cart';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
function App() {
return (
<div className="App">
<BrowserRouter>
<NavBar />
<MoreSell/>
<Routes>
<Route path="/" element={<ItemListContainer/>} />
<Route path="/category/:categoryID" element={<ItemListContainer/>} />
<Route path="/detail/:productID" element={<ItemDetailContainer/>} />
<Route path="/cart" element={<Cart/>} />
<ItemListContainer/>
</Routes>
</BrowserRouter>
</div>
);
}
export default App;
Thank you
ItemListContainer is causing the problem after the Cart route, since inside Routes you can only define route
function App() {
return (
<div className="App">
<BrowserRouter>
<NavBar />
<MoreSell/>
<Routes>
<Route path="/" element={<ItemListContainer/>} />
<Route path="/category/:categoryID" element={<ItemListContainer/>} />
<Route path="/detail/:productID" element={<ItemDetailContainer/>} />
<Route path="/cart" element={<Cart/>} />
</Routes>
</BrowserRouter>
</div>
);
}
export default App;
You have ItemListContainer/> as a child inside Routes>. Either delete this component, move it outside of Routes, or create a new route with it inside.
<Routes>
<Route path="/" element={<ItemListContainer/>} />
<Route path="/category/:categoryID" element={<ItemListContainer/>} />
<Route path="/detail/:productID" element={<ItemDetailContainer/>} />
<Route path="/cart" element={<Cart/>} />
<ItemListContainer/> //<-------------------------This is the error
</Routes>
I think the answer in your error message:
you need to remove < ItemListContainer /> from < Routes > ... </ Routes > container and move it to another place. For example:
function App() {
return (
<div className="App">
<BrowserRouter>
<NavBar />
<MoreSell/>
<Routes>
<Route path="/" element={<ItemListContainer/>} />
<Route path="/category/:categoryID" element={<ItemListContainer/>} />
<Route path="/detail/:productID" element={<ItemDetailContainer/>} />
<Route path="/cart" element={<Cart/>} />
</Routes>
<ItemListContainer/>
</BrowserRouter>
</div>
);
}

index.tsx:24 Uncaught Error: useLocation() may be used only in the context of a <Router> component

I am using use location to hide the navbar if the pathname name is /admin, /employee, /publisher. but I got an error saying that Error: useLocation() may be used only in the context of a <Router> component.
This is My App.js
import { BrowserRouter as Router, Routes, Route, useLocation } from 'react-router-dom';
import Navbar from './components/Navbar';
function App() {
const location = useLocation()
return (
<>
<UserState>
<Router>
{!["/admin", "/employee", "/publisher"].includes(location.pathname) && <Navbar/>} //For to hide the navbar if the pathname is /admin, /employee, /publisher
<Routes onUpdate={() => window.scrollTo(0, 0)}>
<Route exact path="/" element={<Home />} />
<Route exact path="/service" element={<Service />} />
<Route exact path="/contact" element={<Contact />} />
<Route exact path="/login" element={<Login />} />
<Route exact path="/reset" element={<Reset />} />
<Route exact path="/reset/:token" element={<Newpassword />} />
<Route path="*" element={<NoteFound/>} />
{/* admin pages */}
<Route path="/admin" element={<Admin />}>
<Route path="add-project" element={<Addproject />} />
<Route path="all-user" element={<AllUser />} />
</Route>
{/* Publisher dasboard */}
<Route path="/publisher" element={<Publisher />}>
<Route path="project-status" element={<ProjectStatus />} />
<Route path="allpublise" element={<Allpublise />} />
</Route>
</Route>
</Routes>
</Router>
</UserState>
</>
);
}
export default App;
The useLocation hook (and all other react-router-dom hooks) need a router above it in the ReactTree so that a routing context is available.
2 options:
Move the Router component up the tree and wrap the App component so it can use the useLocation hook.
import { BrowserRouter as Router } from 'react-router-dom';
...
<Router>
<App />
</Router>
...
import { Routes, Route, useLocation } from 'react-router-dom';
import Navbar from './components/Navbar';
function App() {
const location = useLocation();
return (
<UserState>
{!["/admin", "/employee", "/publisher"].includes(location.pathname) && <Navbar/>}
<Routes onUpdate={() => window.scrollTo(0, 0)}>
<Route path="/" element={<Home />} />
<Route path="/service" element={<Service />} />
<Route path="/contact" element={<Contact />} />
<Route path="/login" element={<Login />} />
<Route path="/reset" element={<Reset />} />
<Route path="/reset/:token" element={<Newpassword />} />
<Route path="*" element={<NoteFound/>} />
{/* admin pages */}
<Route path="/admin" element={<Admin />}>
<Route path="add-project" element={<Addproject />} />
<Route path="all-user" element={<AllUser />} />
</Route>
{/* Publisher dasboard */}
<Route path="/publisher" element={<Publisher />}>
<Route path="project-status" element={<ProjectStatus />} />
<Route path="allpublise" element={<Allpublise />} />
</Route>
</Routes>
</UserState>
);
}
export default App;
Move the useLocation hook down the tree so that it's used within the Router component.
import { Routes, Route, useLocation } from 'react-router-dom';
import Navbar from './components/Navbar';
function App() {
return (
<UserState>
<Router>
<Navbar/>
<Routes onUpdate={() => window.scrollTo(0, 0)}>
<Route path="/" element={<Home />} />
<Route path="/service" element={<Service />} />
<Route path="/contact" element={<Contact />} />
<Route path="/login" element={<Login />} />
<Route path="/reset" element={<Reset />} />
<Route path="/reset/:token" element={<Newpassword />} />
<Route path="*" element={<NoteFound/>} />
{/* admin pages */}
<Route path="/admin" element={<Admin />}>
<Route path="add-project" element={<Addproject />} />
<Route path="all-user" element={<AllUser />} />
</Route>
{/* Publisher dasboard */}
<Route path="/publisher" element={<Publisher />}>
<Route path="project-status" element={<ProjectStatus />} />
<Route path="allpublise" element={<Allpublise />} />
</Route>
</Routes>
</Router>
</UserState>
);
}
export default App;
...
const Navbar = () => {
const location = useLocation();
return !["/admin", "/employee", "/publisher"].includes(location.pathname)
? /* Return navbar JSX here */
: null;
};
useLocation() hook is used to extract the current location from the router.
For this purpose it's need the router context to pass the Location content
So if you want to use this hook, you need to use it in one of the nested components in <Router> Provider.
For your situation, you need to move the hook into the navbar component.
import { useLocation } from 'react-router-dom';
function Navbar() {
const location = useLocation()
if(["/admin", "/employee", "/publisher"].includes(location.pathname))
return <></>
return (
<>
I'm a navbar
</>
);
}
export default Navbar;

Detect the url (on reactjs) to hide an element on the page

On a project I just started on reactjs, I should hide an element when the url changes. I searched and did not find something useful.
I would like to hide the Sidebar when the url is not Search.
Thanks to anyone who wants to give me a hand.
import React from 'react';
import { Routes, Route } from "react-router-dom";
import 'bootstrap/dist/css/bootstrap.css';
import 'react-bootstrap';
import './App.css';
import NavBarTop from './components/layouts/header/NavBar_top';
import Sidebar from './components/layouts/Sidebar';
import Home from './components/pages/Home';
import Login from './components/pages/Login';
import Register from './components/pages/Register';
import Search from './components/pages/Search';
import E404 from './components/pages/E404';
function App() {
return (
<>
<div>
<NavBarTop />
<div className="container-fluid maincon">
<Sidebar />
<Routes>
<Route path="/" exact element={<Home />} />
<Route path="/login" element={<Login />} />
<Route path="/register" element={<Register />} />
<Route path="/search" element={<Search />} />
<Route path="*" element={<E404 />} />
</Routes>
</div>
</div>
</>
);
}
export default App;
I would like to hide the Sidebar when the url is not Search.
Just render the Sidebar only with the Search component instead of unconditionally with everything.
<div>
<NavBarTop />
<div className="container-fluid maincon">
<Routes>
<Route path="/" element={<Home />} />
<Route path="/login" element={<Login />} />
<Route path="/register" element={<Register />} />
<Route
path="/search"
element={(
<>
<Sidebar />
<Search />
</>
)}
/>
<Route path="*" element={<E404 />} />
</Routes>
</div>
</div>
If you wanted to render Sidebar with several routes, then create a layout component. Nested/wrapped Route components are rendered into the Outlet component.
import { Outlet } from 'react-router-dom';
const SidebarLayout = () => (
<>
<Sidebar />
<Outlet />
</>
);
...
<div>
<NavBarTop />
<div className="container-fluid maincon">
<Routes>
<Route path="/" element={<Home />} />
<Route path="/login" element={<Login />} />
<Route path="/register" element={<Register />} />
<Route element={SidebarLayout}>
<Route path="/search" element={<Search />} />
... other routes to render with sidebar ...
</Route>
<Route path="*" element={<E404 />} />
</Routes>
</div>
</div>
there are multiple ways to do that.. this is only one...
export default function Wrapper() {
const urlWindow = window.location;
console.log(urlWindow.pathname.split("/")[1]);
const acceptedPaths = ["login", "register", "search", "test"];
return (
<>
<div>
navbar
<div className="container-fluid">
<div className="row">
{acceptedPaths.includes(urlWindow.pathname.split("/")[1]) ? (
<>
<Sidebar />
<MainContent />
</>
) : "Show 404 page"}
</div>
</div>
</div>
</>
);
}
const Sidebar = () => {
return <div className="col-md-2">I'm sidebar</div>;
};
const MainContent = () => {
return <div className="col-md-10">I'm main content</div>;
};
Firstly, you need import useLocation in react-router-dom
import { Routes, Route, useLocation } from "react-router-dom";
and call it in App function to get the current URL path which is used to check against /search for hiding/showing SideBar
function App() {
const location = useLocation();
const currentPath = location.pathname
return (
<>
<div>
<NavBarTop />
<div className="container-fluid maincon">
{currentPath === '/search' && <Sidebar />}
<Routes>
<Route path="/" exact element={<Home />} />
<Route path="/login" element={<Login />} />
<Route path="/register" element={<Register />} />
<Route path="/search" element={<Search />} />
<Route path="*" element={<E404 />} />
</Routes>
</div>
</div>
</>
);
}
you can use hook named as useSearchParam
const [searchParams, setSearchParams] = useSearchParams();
to get query/url params as string.

How to hide Footer component for some pages in react

i would like to hide footer component in some page
app.js
<div className="App">
<Header setShowMenu={setShowMenu} />
{showMenu ? <Menu navigateTo={navigateTo} setShowMenu={setShowMenu} /> : null}
<Main navigateTo={navigateTo} />
<Footer navigateTo={navigateTo} />
</div>
main.jsx
<div>
<Routes>
<Route path="/" element={<HomePage navigateTo={navigateTo} />} />
<Route path="/precard" element={<PreCard />} />
<Route path="/order" element={<Order />} />
<Route path="/contact" element={<Contact />} />
<Route path="/thankspage" element={<ThanksPage navigateTo={navigateTo}/>} />
<Route path="/*" element={<HomePage />} />
</Routes>
</div>
Note: The Router in index.js
So I want to hide the footer in ./order Page
I hope you guys have solution for me :)
You can use useLocation() hook to check the route path in the <Footer /> component and based on the pathname you can render the <Footer /> component.
Example :
import React from "react";
import { useLocation } from "react-router-dom";
const Footer = () => {
const { pathname } = useLocation();
console.log(pathname);
// you can check a more conditions here
if (pathname === "/thanks") return null;
return <div className="footer">Footer</div>;
};
export { Footer };
App.js
import { Route, Switch, BrowserRouter } from "react-router-dom";
import "./styles.css";
import { Home } from "./pages/Home";
import { Catalog } from "./pages/Catalog";
import { Thanks } from "./pages/Thanks";
import { Header } from "./components/Header";
import { Footer } from "./components/Footer";
import { Page404 } from "./pages/Page404";
const App = () => {
return (
<>
<BrowserRouter>
<Header />
<Switch>
<Route path={"/"} exact>
<Home />
</Route>
<Route path={"/catalog"} exact>
<Catalog />
</Route>
<Route path={"/thanks"} exact>
<Thanks />
</Route>
<Route path={"*"}>
<Page404 />
</Route>
{/* <Redirect to={'/'} /> */}
</Switch>
<Footer />
</BrowserRouter>
</>
);
};
export { App };

Categories