useNavigate 未在登录 v6 react-router-dom 上重定向

时间:2020-12-28 20:21:57

标签: reactjs redirect react-router-dom

在提交表单时,useNavigate 钩子应该检测到 isAuthenticated 状态并重定向到“/app/dashboard”路由,但它仍然在“/login”路由上

App.js 这里 isAuthenticated 传递给路由并根据其全局布尔值呈现相关路由

import React from "react";
import jwtDecode from "jwt-decode";

// Routing
import { useRoutes } from "react-router-dom";
import routes from "./routes"

const token = localStorage.FBIdToken;

let isAuthenticated;

if (token) {
  const decodedToken = jwtDecode(token);
  console.log(decodedToken);
  //  Check whether the token is expired
  if (decodedToken.exp * 1000 < Date.now()) {
    window.location.href = "/login";
    isAuthenticated = false;
  } else {
    isAuthenticated = true;
  }
}

function App() {
  const routing = useRoutes(routes(isAuthenticated));

  return (
    <ThemeProvider theme={theme}>
      <GlobalStyles />
      {routing}
    </ThemeProvider>
  );
}

export default App;

routes.js 传递 isAuthenticated 以确定将显示哪个视图

import React from "react";
import { Navigate } from "react-router-dom";
const routes = (isAuthenticated) => [
  {
    path: "/app",
    element:
      isAuthenticated === true ? <DashboardLayout /> : <Navigate to="/login" />,
    children: [{ path: "dashboard", element: <Dashboard /> }],
  },
  {
    path: "/",
    element: !isAuthenticated ? (
      <MainLayout />
    ) : (
      <Navigate to="/app/dashboard" />
    ),
    children: [
      { path: "login", element: <Login /> },
      { path: "signup", element: <Signup /> },
      { path: "/", element: <Navigate to="/app/dashboard" /> },
    ],
  },
];

export default routes;

login.js 发送了一个 axios 请求,成功的响应应该会导致页面重定向到“/app/dashboard”路由

import React, { useState } from "react";
import { Link as RouterLink, useNavigate } from "react-router-dom";
const Login = () => {
  const classes = useStyles();
  const navigate = useNavigate();

  const [state, setState] = useState({
    email: "",
    password: "",
    loading: false,
    errors: {},
  });

  const handleChange = (e) => {
    // Set the value of state to corresponding input
    setState({
      ...state,
      [e.target.name]: e.target.value,
    });
  };

  const handleSubmit = (e) => {
    e.preventDefault();

    setState({
      ...state,
      loading: true,
    });

    const userData = {
      email: state.email,
      password: state.password,
    };

    axios
      .post("/login", userData)
      .then((response) => {
        console.log(response.data);

        localStorage.setItem("FBIdToken", `Bearer ${response.data.token}`);

        setState({
          ...state,
          loading: false,
        });

        navigate("/app/dashboard", { replace: true });
      })
      .catch((err) => {
        setState({
          ...state,
          errors: err.response.data,
          loading: false,
        });
      });
  };

  return (
    // Some form
  );
};

export default Login;

2 个答案:

答案 0 :(得分:0)

我采用的方法很脏,但它对历史版本 5.0.0 仍然有效

src/utils/history.js

import { createBrowserHistory } from "history"
export default createBrowserHistory();

src/pages/auth/login.js

import React, { useState } from "react";
import { Link as RouterLink} from "react-router-dom";
import history from "../../utils/histroy";

const Login = () => {
  const classes = useStyles();
  const navigate = useNavigate();

  const [state, setState] = useState({
    email: "",
    password: "",
    loading: false,
    errors: {},
  });

  const handleChange = (e) => {
    // Set the value of state to corresponding input
    setState({
      ...state,
      [e.target.name]: e.target.value,
    });
  };

  const handleSubmit = (e) => {
    e.preventDefault();

    setState({
      ...state,
      loading: true,
    });

    const userData = {
      email: state.email,
      password: state.password,
    };

    axios
      .post("/login", userData)
      .then((response) => {
        console.log(response.data);

        localStorage.setItem("FBIdToken", `Bearer ${response.data.token}`);

        setState({
          ...state,
          loading: false,
        });

        history.push("/app/dashboard");
        histrory.go();
      })
      .catch((err) => {
        setState({
          ...state,
          errors: err.response.data,
          loading: false,
        });
      });
  };

  return (
    // Some form
  );
};

export default Login;

答案 1 :(得分:0)

useNavigate 没有问题。问题是传递给我的路由的布尔参数。这是我解决它的方法

创建了一个名为 src/redux/reducers/authReducer 的文件

import * as actionType from "../types";

let decodedUser = localStorage.getItem("SomeToken");

//  Initialize state to match auth state
const initialState = decodedUser
  ? { isAuthenticated: true }
  : { isAuthenticated: false };

export default function (state = initialState, action) {
  switch (action.type) {
    case actionType.SET_AUTHENTICATED:
      return {
        ...state,
        isAuthenticated: true,
      };

    //  Unauthenticated is in the userReducer

    default:
      return state;
  }
}

将reducer持久化到store中的组合reducer

const reducers = combineReducers({
  
  auth: authReducer,
});

然后在 App.js 中执行以下操作

function App() {
  const { isAuthenticated } = useSelector((state) => state.auth);

  const routing = useRoutes(routes(isAuthenticated));

  return (
  <div>Some filler code</div>
  );
}

然后在正在执行的操作中调用操作类型。例如

userAction.js

import * as actionType from "../types";
export const login = (data) => (dispatch) =>{
   dispatch({type: actionType.SET_AUTHENTICATED });
}

参考:https://bezkoder.com/react-hooks-redux-login-registration-example/