繁体   English   中英

react js用户在刷新时被重定向到另一个页面

[英]react js user gets redirected to another page on refresh

我有一个带有 react-router-dom v6 的 react js 应用程序来处理路由。 在我添加 firebase firestore 之前,路由功能工作得很好,但现在由于某种原因,当我在搜索页面并重新加载它时,主页会被渲染。 用户身份验证不是问题,因为这是由登录组件处理的,但我在配置中找不到问题。

这是我的应用程序组件。

import React, {useEffect, useState} from "react";
import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom";
import { createBrowserHistory } from 'history';
import ReactDOM from "react-dom";
import "./styles/style.scss";
import Home from "./pages/home";
import Seeker from "./pages/seeker";
import NotFound from "./pages/notFound";
import Login from "./pages/login";


const App = () => {
    const [token, setToken] = useState(false);

  useEffect(() => {
      if(localStorage.getItem("token") === null){
        setToken(false);
      } else {
        setToken(true);
      }
  }, [])

    return (
        <BrowserRouter history={createBrowserHistory}> 
        <Routes>
            <Route exact path="/" element={<Login isAuth={token}/>}/>
            <Route exact path="/home" element={token ? <Home /> : <Navigate to="/"/>}/> 
            <Route exact path="/seeker" element={token ? <Seeker /> : <Navigate to="/"/>}/> 
            <Route path="*" element={<NotFound />}/>
        </Routes>   
    </BrowserRouter>
) 
}
 

ReactDOM.render(
        <App />,
    document.getElementById("root"))



登录组件在 localstorage 上正确设置令牌,并且路由使用它来有条件地呈现组件。 但是当我在“/seeker”url 中时,刷新会将我带到“/home”。

import React, { useState, useEffect } from "react";
import { Formik, Form, Field, ErrorMessage } from 'formik';
import axios from "axios";
require("babel-core/register");
require("babel-polyfill");
import GridRender from "../components/gridRender";
import { NavBar } from "../components/navBar";

async function getHeros(name) {
    return await axios.get(
        `https://www.superheroapi.com/api.php/${name}`
    );
} 

const Seeker = () => {    
    
    const [searchedHero, setSearchedHero] = useState("")
    const [matchedHeros, setMatchedHeros] = useState([]); 


    useEffect(() => {
        let isMounted = true; 
        if (isMounted) {
        getHeros(searchedHero).then((heros) => {
            const hero = heros.data.response != "error" ? heros.data.results : []
            localStorage.setItem("addHeroAction", "true");
            setMatchedHeros(hero);
        }, console.error);
    }
    return () => { isMounted = false };
    }, [searchedHero]);

    return (
        <div>
            <NavBar />
            <div className="seeker">
                <h1 className="title">Find your next teammate!</h1>
                <Formik /> //// here is a large form that i erased so it doesn't get long
                {matchedHeros.length != 0 && <GridRender matchedHeros = {matchedHeros}/>}
            </div>
        </div>
        )
    } 


export default Seeker; 

这是我的 firebase 配置(我使用版本 9)以防万一,因为在 firebase 实施之后出现了错误。

import { initializeApp } from "firebase/app";
import "regenerator-runtime/runtime";
import { addDoc, deleteDoc, doc } from 'firebase/firestore';
import { getFirestore, collection } from 'firebase/firestore'


const firebaseConfig = {
  apiKey: "xxxxxxxxxxxxxxxxxx",
  authDomain: "xxxxxxxxxxxxxxxxxxxx",
  databaseURL: "xxxxxxxxxxxxxxxxxxxxx",
  projectId: "superteam-maker",
  storageBucket: "xxxxxxxxxxxxxxx",
  messagingSenderId: "xxxxxxxxxxxxx",
  appId: "xxxxxxxxxxxxxxxxxxxxxxxxxx"
};

initializeApp(firebaseConfig);
const db = getFirestore();
const colRef = collection(db, "team")


const addHero = (hero) => {
    addDoc(colRef, {
            name : hero.name,
            powerstats :{
                combat: parseInt(hero.powerstats.combat),
                durability: parseInt(hero.powerstats.durability), 
                intelligence: parseInt(hero.powerstats.intelligence),
                power: parseInt(hero.powerstats.power),
                speed: parseInt(hero.powerstats.speed),
                strength : parseInt(hero.powerstats.strength)
            },
            id: parseInt(hero.id),
            image: {url : hero.image.url},
            
    } )
}

const deleteHero = (hero) => {
    const docRef = doc(db, "team", hero.id);
    deleteDoc(docRef);
}


export {addHero, deleteHero, colRef}

////////更新/////////

登录组件使用返回随机令牌的测试 API 对用户进行身份验证,因此用户只有在提交某个 email 和密码后才能进入。 如果身份验证成功,用户将被呈现到“/home”。

这是登录组件的代码。

import React, {useEffect, useState} from "react";
import { Formik } from 'formik';
import { Navigate } from 'react-router-dom';
import axios from "axios";


const Login = (props) => {
  const [token, setToken] = useState(false);

  useEffect(() => {
      if(localStorage.getItem("token") === null){
        setToken(false);
      } else {
        setToken(true);
      }
  }, []) 


  const verification = () => {
    if( token && props.isAuth){
      return <Navigate to="/home"/>
    }
  }

    let logInError = {};
    return(
      <div className="login__background">
        <div className="login container">
          {verification()}
          <h1 className="display-1 title login__title">Make a team as <span>powerfull</span> as you!</h1>
          <h5 className="login-title__sub">Please log in to create your superteam</h5>
            <Formik
            initialValues={{ email: '', password: '' }}
            validate={values => {
            const errors = {};
            
            if (!values.email) {
              errors.email = 'Required';
            } else if (
              !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)
            ) {
              errors.email = 'Invalid email address';
            } 
            
            if (!values.password){
                errors.password = "Required";
            } 
            return errors;
            }}
            onSubmit={(values) => {
                axios.post("http://challenge-react.alkemy.org/", values)
                .then(response => {
                    let token = response.data.token
                    localStorage.setItem("token", token);
                    localStorage.setItem("addHeroAction", false);
                    setToken(true);
                    return <Navigate to="/home"/>
                })
                .catch(error => {
                    if (error.response) {
                        logInError = error.response.data.error;
                        window.alert(logInError);
                      } else if (error.request) {
                        console.log(error.request);
                      } else {
                        console.log('Error', error.message);
                      }
                      console.log(error.config);
                })
            }}>

            {({
              values,
              errors,
              touched,
              handleChange,
              handleBlur,
              handleSubmit
            }) => (
            <form onSubmit={handleSubmit}>
                <label className="form-label label" name="email">Email</label>
                <br />
              <input
                className="form-control form-control-lg input"
                type="email"
                name="email"
                onChange={handleChange}
                onBlur={handleBlur}
                value={values.email}
              />
              {errors.email && touched.email && errors.email}
              <br />
              <label className="form-label label " name="password">Password</label>
              <br />
              <input
                className="form-control form-control-lg input"
                type="password"
                name="password"
                onChange={handleChange}
                onBlur={handleBlur}
                value={values.password}
              />
              {errors.password && touched.password && errors.password}
              <br />
              <button type="submit" className="btn btn-danger">
                Submit
              </button>
            </form>
            )}
            </Formik>
            
        </div>
      </div>
    )

}

export default Login;

它还会从 App.js 获取 IsAuth 属性,以防这是用户第一次进入页面并且没有保存令牌。

我看到的问题是token state 最初是错误的。 useEffect在渲染周期结束时运行,因此初始渲染token为 false

const [token, setToken] = useState(false);

useEffect(() => {
  if (localStorage.getItem("token") === null) {
    setToken(false);
  } else {
    setToken(true);
  }
}, []);

并且使用token state 呈现的任何Route都将使用此初始false值并采取相应措施。

<Route path="/seeker" element={token ? <Seeker /> : <Navigate to="/" />} /> 

如果在"/seeker"路径上并且token值为false ,则呈现Navigate组件。

假设您的所有身份验证流程都正确且有效,并将token值设置为 localStorage,那么您应该localStorage 初始化token state。

const initializeState = () => !!JSON.parse(localStorage.getItem("token"));

const [token, setToken] = useState(initializeState);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM