skip to Main Content

Hello dear stackoverflow users. First of all, thank you in advance for your help. I have a react application in this application, I check the user login process when going to the /admin page, if the user is not logged in, I redirect to the /login page. I log in the user by making a request on the backend and create a token. If the user login is successful, I try to redirect to the /admin page, but I get an error. I haven’t been able to solve it yet. I am sharing my codes with you.

router/index.jsx

  import { createBrowserRouter } from "react-router-dom";
import WebLayout from "~/../layouts/web";
import AdminLayout from "~/../layouts/admin";
import Home from "~/pages/web/home";
import Orders from "~/pages/admin/orders";
import Categories from "~/pages/admin/categories";
import Tables from "~/pages/admin/tables";
import Meals from "~/pages/admin/meals";
import AdminHome from "~/pages/admin/home";
import MealDetail from "~/pages/web/mealdetail";
import Login from "~/components/shared/login";
import PrivateRoute from "~/components/shared/privateroute";

const routes = createBrowserRouter([
  {
    path: "/login",
    element: <Login />,
  },
  {
    path: "/",
    element: <WebLayout />,
    children: [
      {
        index: true,
        element: <Home />,
      },
      {
        path: "meal/:mealId",
        element: <MealDetail />,
      },
    ],
  },
  {
    path: "/admin",
    element: <AdminLayout />,
    children: [
      {
        index: true,
        element: <PrivateRoute component={AdminHome} />,
      },
      {
        path: "orders",
        element: <PrivateRoute component={Orders} />,
      },
      {
        path: "categories",
        element: <PrivateRoute component={Categories} />,
      },
      {
        path: "tables",
        element: <PrivateRoute component={Tables} />,
      },
      {
        path: "meals",
        element: <PrivateRoute component={Meals} />,
      },
    ],
  },
]);

export default routes;

privateroute/index.jsx

import React from "react";
import { Route, Navigate } from "react-router-dom";
import { useSelector } from "react-redux";

const PrivateRoute = ({ element: Element, ...rest }) => {
  const isAuthenticated = useSelector((state) => state.auth.isAuthenticated);
  return isAuthenticated ? (
    <Route {...rest} element={<Element />} />
  ) : (
    <Navigate to="/login" />
  );
};

export default PrivateRoute;

login/index.jsx

import React, { useState } from "react";
import { useDispatch } from "react-redux";
import { loginAsync } from "~/store/authSlice";
import { useNavigate } from "react-router-dom"; // useNavigate hook'unu ekleyin

const Login = () => {
  const dispatch = useDispatch();
  const navigate = useNavigate(); // useNavigate hook'unu tanımlayın
  const [username, setUsername] = useState("");
  const [password, setPassword] = useState("");

  const handleLogin = async () => {
    try {
      // Redux Toolkit ile login işlemini gerçekleştiren action çağrısı
      await dispatch(loginAsync({ username, password }));
      // Login başarılı olduğunda /admin sayfasına yönlendir
      navigate("/admin"); // useNavigate hook'unu kullanarak yönlendirme işlemini gerçekleştirin
    } catch (error) {
      console.error("Login error:", error.message);
      // Handle login error, display a message to the user, etc.
    }
  };

  return (
    <div>
      <input
        type="text"
        placeholder="Username"
        value={username}
        onChange={(e) => setUsername(e.target.value)}
      />
      <input
        type="password"
        placeholder="Password"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
      />
      <button onClick={handleLogin}>Login</button>
    </div>
  );
};

export default Login;

authslice.js

   // src/store/authSlice.js
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import axios from 'axios';

const initialState = {
    token: null,
    username: null,
    isAuthenticated: false,
};


export const loginAsync = createAsyncThunk('auth/login', async ({ username, password }) => {
    try {

        const response = await axios.post('http://localhost:3000/api/login', {
            username,
            password,
        });
        console.log(response.data);

        const data = response.data;
        return { token: data.token, username };
    } catch (error) {

        throw new Error(error.response.data.error);
    }
});

const authSlice = createSlice({
    name: 'auth',
    initialState,
    reducers: {
        logout(state) {
            state.token = null;
            state.username = null;
            state.isAuthenticated = false;
        },
    },
    extraReducers: (builder) => {

        builder.addCase(loginAsync.fulfilled, (state, action) => {
            const { token, username } = action.payload;
            state.token = token;
            state.username = username;
            state.isAuthenticated = true;
        });
    },
});

export const { logout } = authSlice.actions;
export default authSlice.reducer;

and finally the error i got

Unexpected Application Error!
A <Route> is only ever to be used as the child of <Routes> element, never rendered directly. Please wrap your <Route> in a <Routes>.
Error: A <Route> is only ever to be used as the child of <Routes> element, never rendered directly. Please wrap your <Route> in a <Routes>.
    at invariant (http://localhost:5173/node_modules/.vite/deps/react-router-dom.js?v=9572ed87:202:11)
    at Route (http://localhost:5173/node_modules/.vite/deps/react-router-dom.js?v=9572ed87:3706:10)
    at renderWithHooks (http://localhost:5173/node_modules/.vite/deps/chunk-UHLQBSTO.js?v=9572ed87:12171:26)
    at mountIndeterminateComponent (http://localhost:5173/node_modules/.vite/deps/chunk-UHLQBSTO.js?v=9572ed87:14921:21)
    at beginWork (http://localhost:5173/node_modules/.vite/deps/chunk-UHLQBSTO.js?v=9572ed87:15902:22)
    at beginWork$1 (http://localhost:5173/node_modules/.vite/deps/chunk-UHLQBSTO.js?v=9572ed87:19749:22)
    at performUnitOfWork (http://localhost:5173/node_modules/.vite/deps/chunk-UHLQBSTO.js?v=9572ed87:19194:20)
    at workLoopSync (http://localhost:5173/node_modules/.vite/deps/chunk-UHLQBSTO.js?v=9572ed87:19133:13)
    at renderRootSync (http://localhost:5173/node_modules/.vite/deps/chunk-UHLQBSTO.js?v=9572ed87:19112:15)
    at recoverFromConcurrentError (http://localhost:5173/node_modules/.vite/deps/chunk-UHLQBSTO.js?v=9572ed87:18732:28)
💿 Hey developer 👋

You can provide a way better UX than this when your app throws errors by providing your own ErrorBoundary or errorElement prop on your route.

2

Answers


  1. I think your error message already lets you know how to fix the code? To wrap your Route in Routes

    Anyways this qn here should help you with your problem as well

    Error "Error: A <Route> is only ever to be used as the child of <Routes> element"

    Login or Signup to reply.
  2. Change your route to:

            element: <PrivateRoute>YourComponents</PrivateRoute>,
    
    

    and private Route return statement from

      return isAuthenticated ? (
        <Route {...rest} element={<Element />} />
      ) : (
        <Navigate to="/login" />
      );
    

    to

      return isAuthenticated ? (
            <>
              {children}
              <Outlet />
            </>  ) : (
        <Navigate to="/login" />
      );
    

    Once you render the route, your private route element should render the children in the private route and the Outlet for other nested routes.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search