I am making a login application when i am clicking the login button the i am reciving an error (loginPage.js:33 Uncaught (in promise) TypeError: setLoginUser is not a function)
here is the code of app.js
function App() {
const [user,setLoginUser] = useState({})
return(
<div className='App'>
<BrowserRouter>
< Routes>
<Route path="/homepage" element={user && user?._id? <Homepage /> : <Login setLoginUser={setLoginUser} />}/>
<Route path="/login" element={<Login />} setLoginUser={setLoginUser}/>
<Route path="/register" element={<Register />} />
</Routes>
</BrowserRouter>
</div>
)
}
and here is the code of loginPage.js where error is occuring
const Login = ({ setLoginUser }) => {
const login = () => {
axios.post("http://localhost:4000/login", user)
.then(res => {
alert(res.data.message)
console.log(res.data.user)
setLoginUser(res.data.user)
navigate('/homepage')
})
}
}
You have to pass your setLoginUser function to Login component in your routes.
<Route path="/login" element={<Login setLoginUser={setLoginUser} />} />
You should replace :
<Route path="/login" element={<Login />} setLoginUser={setLoginUser}/>
by
<Route path="/login" element={<Login setLoginUser={setLoginUser}/>} />
I don't think it's a good idea to path variable like that in the root element but this should works.
Why do you have <BrowserRouter> and <Routes> ?
Related
This question already has answers here:
How to create a protected route with react-router-dom?
(5 answers)
Closed last month.
Error
Uncaught Error: A is only ever to be used as the child of element, never rendered directly. Please wrap your in a .
Private Router
function PrivateRoute({ children, ...rest }) {
const auth = useAuth();
return (
<Route
{...rest}
render={() => {
if(auth.user){
return children;
}
return <Navigate to='/login' />
}}
/>
);
}
App.js
return (
<div className="App">
<Router>
<Navbar />
<Routes>
<Route exact path="/" element={<Home />} />
<Route exact path="/login" element={<Login />} />
<Route exact path="/register" element={<Signup />} />
<Route exact path="/settings" element={<PrivateRoute><Settings /></PrivateRoute>} />
<Route element={<Page404 />} />
</Routes>
</Router>
</div>
);
I was trying to Privating the route for settings , but got error.
Can you try to replace your settings route by this :
<Route exact path="/settings" component={PrivateRoute}><Settings /></Route>
in requestmethods.js
import axios from "axios";
const BASE_URL = "http://localhost:5000/api/";
const TOKEN = JSON.parse(JSON.parse(localStorage.getItem("persist:root"))?.user)
?.currentUser?.accessToken;
export const publicRequest = axios.create({
baseURL: BASE_URL,
});
export const userRequest = axios.create({
baseURL: BASE_URL,
headers: { token: `Bearer ${TOKEN}` },
});
and in app.js
function App() {
const admin = useSelector((state) => state.user.currentUser.isAdmin);
return (
<Router>
<Switch>
<Route path="/login">
<Login />
</Route>
{admin && (
<>
<Topbar />
<div className="container">
<Sidebar />
<Route exact path="/">
<Home />
</Route>
<Route path="/users">
<UserList />
</Route>
<Route path="/user/:userId">
<User />
</Route>
<Route path="/newUser">
<NewUser />
</Route>
<Route path="/products">
<ProductList />
</Route>
<Route path="/product/:productId">
<Product />
</Route>
<Route path="/newproduct">
<NewProduct />
</Route>
</div>
</>
)}
</Switch>
</Router>
);
}
I am trying to make if the user is admin show the admin pages, if not show the login page , but when I run npm start I get blank screen , when inspect the page I get these types of error
1=> Uncaught TypeError: state.user.currentUser is null
const admin = useSelector((state) => state.user.currentUser.isAdmin);
Uncaught TypeError: state.user.currentUser is null
This states that the currentUser property in your state.user object is null hence it cannot read the isAdmin property.
One way to avoid this use the safe(elvis) operator '?'.
So use state?.user?.currentUser?.isAdmin instead of state.user.currentUser.isAdmin
Assuming you are using react-router v6, your app.js could look like this
function App() {
const admin = useSelector((state) => state?.user?.currentUser?.isAdmin);
const RequireAuth = () => {
if (!admin) {
return Navigate('/login');
}
return <Outlet/>;
};
return (
<Router>
<Switch>
<Route path="/login">
<Login />
</Route>
<Topbar />
<div className="container">
<Sidebar />
<Route element={<RequireAuth />}>
<Route exact path="/">
<Home />
</Route>
<Route path="/users">
<UserList />
</Route>
<Route path="/user/:userId">
<User />
</Route>
<Route path="/newUser">
<NewUser />
</Route>
<Route path="/products">
<ProductList />
</Route>
<Route path="/product/:productId">
<Product />
</Route>
<Route path="/newproduct">
<NewProduct />
</Route>
</Route>
</div>
</Switch>
</Router>
);
}
You have a good article here
I'm using React Router v6 and am creating private routes for my application.
In file Route.js, I've the code
export default function RouteWrapper({
element: Element,
isPrivate,
...rest
}) {
const { signed, loading } = useContext(AuthContext);
if (loading) {
return <div></div>;
}
if (!signed && isPrivate) {
return <Navigate to="/" />;
}
if (signed && !isPrivate) {
return <Navigate to="/dashboard" />;
}
return <Route {...rest} render={(props) => <Element {...props} />} />;
}
And in file index.js I've written as:
return (
<Routes>
<Route path="/" element={SignIn} />
<Route path="/register" element={SignUp} />
<Route path="/dashboard" element={Dashboard} isPrivate />
<Route path="/profile" element={Profile} isPrivate />
<Route path="/customers" element={Customers} isPrivate />
<Route path="/new" element={New} isPrivate />
<Route path="/new/:id" element={New} isPrivate />
</Routes>
);
}
Is there something I'm missing?
Issue
RouteWrapper isn't a Route component, and fails an invariant check by react-router-dom.
RouteWrapper is directly rendering a Route component, which if the first invariant wasn't failed would trigger another invariant violation. Route components can only be rendered directly by the Routes component or another Route component in the case of building nested routing.
In short, in react-router-dom#6 custom route components are no longer supported. You should instead use wrapper components/layout routes to handle this use case.
Solution
Convert RouteWrapper to a wrapper component that renders an Outlet component for nested routed components to be rendered into.
Example:
import { Navigate, Outlet } from 'react-router-dom';
export default function RouteWrapper({ isPrivate }) {
const { signed, loading } = useContext(AuthContext);
if (loading) {
return <div></div>;
}
if (!signed && isPrivate) {
return <Navigate to="/" />;
}
if (signed && !isPrivate) {
return <Navigate to="/dashboard" />;
}
return <Outlet />; // <-- nested routes render here
}
Wrap the routes you want to protect with the RouteWrapper.
return (
<Routes>
<Route element={<RouteWrapper />}>
<Route path="/" element={<SignIn />} />
<Route path="/register" element={<SignUp />} />
</Route>
<Route element={<RouteWrapper isPrivate />}>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/profile" element={<Profile />} />
<Route path="/customers" element={<Customers />} />
<Route path="/new" element={<New />} />
<Route path="/new/:id" element={<New />} />
</Route>
</Routes>
);
See Layout Routes for further details.
You should convert
<Routes>
<Route exact path="/" element={Dashboard} />
</Routes>
to
<Routes>
<Route exact path="/" element={<Dashboard/>} />
</Routes>
Also if you want to keep your UI in sync with the URL use like this.
<BrowserRouter>
<Routes>
<Route exact path="/" element={<Dashboard/>} />
</Routes>
</BrowserRouter>
Best.
hello everyone I have an issue with react-router-dom v6.2.1
const MainRoutes = () => {
return (
<Routes>
<Route path={"/"} element={<Login/>}/>
<Route path={"/dashboard*"} render={<PrivateRoutes/>}/>
</Routes>
);
};
const PrivateRoutes = () => {
return (
<Routes>
<Route path="/dashboard/" element={<Dashboard/>}/>
<Route path="/dashboard/:id" element={<Book/>}/>
</Routes>
);
};
/dashboard and /dashboard/:id render blank for me
export const MainRoutes = () => {
return (
<Routes>
<Route path={"/"} element={<Login />} />
<Route path={"/dashboard/*"} element={<PrivateRoutes />} />
</Routes>
);
};
const PrivateRoutes = () => {
return (
<div>
<Routes>
<Route path="/" element={<Dashboard />} />
<Route path="/:id" element={<Book />} />
</Routes>
</div>
);
};
you should use like this
https://reactrouter.com/docs/en/v6/getting-started/overview
hi hasan
you need to change
<Route path={"/dashboard*"} render={<PrivateRoutes/>}/>
to
<Route path={"/dashboard/*"} element={<PrivateRoutes/>}/>
have a look on this post
I have a React Router where some Routes check if the user is logged in. The function calls the backend and returns either true or false. This part is working fine but when i call the function to either render the requested component or the redirect, it always renders the redirect.
function requireAuth() {
axiosInst.post("http://localhost:3001/checkLogged")
.then(function (response) {
if (response.data.user) {
return true
}else{
return false
}
})
}
<Router>
<>
<Navigation/>
<Switch>
<Route path="/login/" exact component={Login} ></Route>
<Route path="/register/" exact component={Register} />
<Route path="/" exact component={Feed} />
<Route path="/articles/" exact component={Feed} />
<Route path="/profile/" >
{requireAuth() ? <Profile/> : <Redirect to="/" />}
</Route>
<Route path="/settings/" component={Settings} />
<Route path="/write/" >
{requireAuth() ? <Write/> : <Redirect to="/" />}
</Route>
<Route path="/search/" component={Search} />
<Route path="/articles/:id" component={ArticleView} />
</Switch>
</>
</Router>
This happens because requireAuth is async and when it returns the boolean, React already rendered the Redirect.
Why don't you use a state variable? Something like:
const [auth, setAuth] = useState(false);
...
function requireAuth() {
axiosInst.post("http://localhost:3001/checkLogged")
.then(function (response) {
if (response.data.user) {
setAuth(true);
return true;
}else{
setAuth(false);
return false;
}
})
}
...
<Router>
<>
<Navigation/>
<Switch>
<Route path="/login/" exact component={Login} ></Route>
<Route path="/register/" exact component={Register} />
<Route path="/" exact component={Feed} />
<Route path="/articles/" exact component={Feed} />
<Route path="/profile/" >
{auth ? <Profile/> : <Redirect to="/" />}
</Route>
<Route path="/settings/" component={Settings} />
<Route path="/write/" >
{auth ? <Write/> : <Redirect to="/" />}
</Route>
<Route path="/search/" component={Search} />
<Route path="/articles/:id" component={ArticleView} />
</Switch>
</>
</Router>
You are making mistake inside requireAuth function. Inside this function then is returning true/false but requireAuth function is not returning anything. So to make requireAuth function return true/false you should return axios value to this function. And also axios returns promises, so to handle promises, it is suggested to use async function
async function requireAuth() {
return await axiosInst.post("http://localhost:3001/checkLogged")
.then(function (response) {
if (response.data.user) {
return true
}else{
return false
}
})
}
And modify your route code to:
....
const [auth, setAuth] = useState(false);
requireAuth().then((res)=>{setAuth(res)})
return(
<Router>
<>
<Navigation/>
<Switch>
<Route path="/login/" exact component={Login} ></Route>
<Route path="/register/" exact component={Register} />
<Route path="/" exact component={Feed} />
<Route path="/articles/" exact component={Feed} />
<Route path="/profile/" >
{auth ? <Profile/> : <Redirect to="/" />}
</Route>
<Route path="/settings/" component={Settings} />
<Route path="/write/" >
{auth ? <Write/> : <Redirect to="/" />}
</Route>
<Route path="/search/" component={Search} />
<Route path="/articles/:id" component={ArticleView} />
</Switch>
</>
</Router>
)