首页 > 解决方案 > 每当我重新加载仪表板时,我的登录组件都会闪烁

问题描述

我正在使用 reactjs 构建具有身份验证和授权的登录/注册系统。如果通过身份验证(jsonwebtoken),它应该将我路由到仪表板,否则将我重定向回登录。但是每当我重新加载它时,它都会在登录端点上停留一秒钟,然后返回仪表板。我怎样才能解决这个问题?

下面是一个显示我在说什么的 giphy

在此处输入图像描述

以下是与上述 App.js问题相关的组件

const App = () => {

  const [isAuthenticated, setIsAuthenticated] = useState(false)
 
  // set isAuthenticated to true or false
  const setAuth = (boolean) => {
    setIsAuthenticated(boolean)
  }

  useEffect(() => {
    // check if the person is still Authenticated
    const isAuth = async () => {
      try {
        const res = await fetch('/auth/verify', {
          method: 'GET',
          headers: { token: localStorage.token},
        })
        const data = await res.json()
       // if authenticated, then
       if(data === true) {
        await setIsAuthenticated(true)
       } else {
        await setIsAuthenticated(false)
       }
      } catch (err) {
        console.error(err.message)
      }
    }
    isAuth()
  })
  
    return (
      <Fragment>
        <Router>
          <div className='container'>
            <Switch>
  
              <Route exact path='/login' render={props => !isAuthenticated ? <Login {...props} setAuth={setAuth} /> : <Redirect to='/dashboard' /> } />
  
              <Route exact path='/register' render={props => !isAuthenticated ? <Register {...props} setAuth={setAuth} /> : <Redirect to='/login' />} />
              
              <Route exact path='/dashboard' render={props => isAuthenticated  ? <Dashboard {...props} setAuth={setAuth} /> : <Redirect to='/login' /> } />
  
            </Switch>
          </div>
        </Router>
      </Fragment>
    );

登录组件

const Login = ({ setAuth }) => {
    const [text, setText] = useState({
        email: '',
        password: ''
    })

    const { email, password } = text

    const onChange = e => setText({ ...text, [e.target.name]: e.target.value})

    const onSubmit = async (e) => {
        e.preventDefault()
        try {
            // Get the body data
            const body = { email, password }
            const res = await fetch('/auth/login', {
                method: 'POST',
                headers: {"Content-Type": "application/json"},
                body: JSON.stringify(body)
            })
            const data = await res.json()
            if(data.token) {
                 // save token to local storage
                localStorage.setItem("token", data.token)
                setAuth(true)
                toast.success('Login Successful')
            } else {
                setAuth(false)
                toast.error(data)
            }
        } catch (err) {
            console.error(err.message)
        }
        
    }
    return (
        <Fragment>
            <h1 className='text-center my-5'>Login</h1>
            <form onSubmit={onSubmit}>

仪表板组件

const Dashboard = ({ setAuth }) => {
    const [name, setName] = useState('')

    useEffect(() => {
        const getName = async () => {
            try {
                const res = await fetch('/dashboard', {
                    method: 'GET', 
                    // Get the token in localStorage into the header
                    headers: { token: localStorage.token }
                })
                const data = await res.json()

                setName(data.user_name)

            } catch (err) {
                console.error(err.message)
            }
        }
        getName()
        // eslint-disable-next-line
    }, [])

    // Log out 
    const logOut = (e) => {
        e.preventDefault()
        localStorage.removeItem("token")
        setAuth(false)
        toast.success('Logged Out')
    }

    return (
        <Fragment>
            <h1 className='mt-5'>Dashboard</h1>
            <p>Hello, {name}</p>
            <button className='btn btn-primary my-3' onClick={e => logOut(e)}>Log Out</button>
        </Fragment>

标签: reactjs

解决方案


我在上面的代码中发现了两个问题。

首先是您的 ueEffect 没有指定任何依赖项。当没有以这种方式指定依赖项时,useEffect 将在任何状态更改时运行。

useEffect(()=> {
 // code here
}); // this one would run anytime any state changes in the component. You usually don't want this.

当指定依赖数组时,useEffect 中的代码将在任何依赖状态发生变化时运行。

useEffect(()=> {
 // code here
},
[state1, state2, ...others...] //code would run when any of the state in this array changes

但是,在您的情况下,您可能希望运行该 useEffect 一次。为此,我们添加一个空数组作为依赖值。

useEffect(()=> {
 // code here
},
[] //empty deps means that the code runs only once. When the component mounts
)

额外的想法

我还建议您向组件添加加载状态,以便在进行 API 调用时显示加载器。

您可能希望在进行 API 调用时显示加载程序(或者甚至默认将此状态设置为 true,因为 API 调用是您在应用程序中执行的第一件事)。

另外,考虑将 useEffect 放在自定义 Hook 中


推荐阅读