简体   繁体   English

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

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

I have a react js app with react-router-dom v6 to handle the routes.我有一个带有 react-router-dom v6 的 react js 应用程序来处理路由。 The routes functionality worked just fine before i added firebase firestore, but now for some reason when i'm in the seeker page and i reload it, the home page gets rendered.在我添加 firebase firestore 之前,路由功能工作得很好,但现在由于某种原因,当我在搜索页面并重新加载它时,主页会被渲染。 It's not a problem with user authentication because that's handled by the login component, but i couldn't find the problem in my configuration.用户身份验证不是问题,因为这是由登录组件处理的,但我在配置中找不到问题。

This is my app component.这是我的应用程序组件。

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"))



The login component sets the token on localstorage correctly and the routes use it to render conditionally the components.登录组件在 localstorage 上正确设置令牌,并且路由使用它来有条件地呈现组件。 But when i'm in the "/seeker" url the refresh takes me to "/home".但是当我在“/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; 

And here is my firebase config (i use version 9) in case it's important because the bug appeared after firebase was implemented.这是我的 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}

////////UPDATE///////// ////////更新/////////

The login component autehnticates the user with a test API that returns a random token, so the user can only enter if a certain email and password get subbmited.登录组件使用返回随机令牌的测试 API 对用户进行身份验证,因此用户只有在提交某个 email 和密码后才能进入。 If the auth is successfull the user gets rendered to "/home".如果身份验证成功,用户将被呈现到“/home”。

Here's the code fro the login component.这是登录组件的代码。

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;

It also gets an IsAuth propr from App.js in case it's the first time the user enters the page and there is no token saved.它还会从 App.js 获取 IsAuth 属性,以防这是用户第一次进入页面并且没有保存令牌。

The issue I see is the token state being initially false.我看到的问题是token state 最初是错误的。 The useEffect runs at the end of the render cycle, so for the initial render token is false useEffect在渲染周期结束时运行,因此初始渲染token为 false

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

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

and any Route being rendered using the token state will use this initial false value and act accordingly.并且使用token state 呈现的任何Route都将使用此初始false值并采取相应措施。

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

If on the "/seeker" path and the token value is false , the Navigate component is rendered.如果在"/seeker"路径上并且token值为false ,则呈现Navigate组件。

Assuming all your authentication flow is correct and working and sets the token value into localStorage then you should initialize the token state from localStorage.假设您的所有身份验证流程都正确且有效,并将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