首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >react...state新手,登录时不更新

react...state新手,登录时不更新
EN

Stack Overflow用户
提问于 2020-10-04 21:46:14
回答 2查看 120关注 0票数 0

在正确的方向上寻找一个温和的推动力。在react项目中工作并使用钩子。是的,已经阅读了文档,但没有完全理解是的。

这个问题是关于登录例程的。登录表单可以工作,但直到重复提交才能反映失败的登录状态;因此,我得到的是以前的状态,而不是当前的状态。

已尝试更改useEffect...no。代码如下,欢迎任何建设性的反馈:

从登录表单

代码语言:javascript
复制
import React, { useState, useEffect, useRef } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { Redirect } from 'react-router-dom'

import getAuthStatus from 'common/cyclone/auth/authenticated.status'

import {
  authenticateByLogin,
  authenticationSelector,
} from '../services/auth.service'

import Form from 'react-validation/build/form'
import Input from 'react-validation/build/input'
import CheckButton from 'react-validation/build/button'

const required = (value) => {
  if (!value) {
    return (
      <div className="alert alert-danger" role="alert">
        This field is required!
      </div>
    )
  }
}

const Login = (props) => {
  const form = useRef()
  const checkBtn = useRef()

  const [username, setUsername] = useState('')
  const [password, setPassword] = useState('')
  const [loading, setLoading] = useState(false)
  const [errorMessage, setErrorMessage] = useState(null)

  const dispatch = useDispatch()

  const { session, hasErrors } = useSelector(authenticationSelector)

  useEffect(() => {}, [session, hasErrors])

  const onChangeUsername = (e) => {
    const username = e.target.value
    setUsername(username)
  }

  const onChangePassword = (e) => {
    const password = e.target.value
    setPassword(password)
  }

  const handleLogin = (e) => {
    e.preventDefault()
    setLoading(true)
    form.current.validateAll()
    if (checkBtn.current.context._errors.length === 0) {
      dispatch(authenticateByLogin(username, password))
        .then(() => {
          setLoading(false)
          if (hasErrors) {
            setErrorMessage(session.error.message)
          } else {
            //props.history.push('/profile')
            // window.location.reload()
          }
        })
        .catch(() => {
          setLoading(false)
        })
    } else {
      setLoading(false)
    }
  }

  if (session.success) {
    //console.log(session.success)
    return <Redirect to="/profile" />
  }

  if (getAuthStatus()) {
    return <Redirect to="/profile" />
  }

  return (
    <div className="col-md-12">
      <div className="card card-container">
        <img
          src="//ssl.gstatic.com/accounts/ui/avatar_2x.png"
          alt="profile-img"
          className="profile-img-card"
        />

        <Form onSubmit={handleLogin} ref={form}>
          <div className="form-group">
            <label htmlFor="username">Username</label>
            <Input
              type="text"
              className="form-control"
              name="username"
              value={username}
              onChange={onChangeUsername}
              validations={[required]}
            />
          </div>

          <div className="form-group">
            <label htmlFor="password">Password</label>
            <Input
              type="password"
              className="form-control"
              name="password"
              value={password}
              onChange={onChangePassword}
              validations={[required]}
            />
          </div>

          <div className="form-group">
            <button className="btn btn-primary btn-block" disabled={loading}>
              {loading && (
                <span className="spinner-border spinner-border-sm"></span>
              )}
              <span>Login</span>
            </button>
          </div>

          {hasErrors && (
            <div className="form-group">
              <div className="alert alert-danger" role="alert">
                {errorMessage}
              </div>
            </div>
          )}
          <CheckButton style={{ display: 'none' }} ref={checkBtn} />
        </Form>
      </div>
    </div>
  )
}

export default Login

从身份验证片:

代码语言:javascript
复制
/** Third Party Libraries */
import { createSlice } from '@reduxjs/toolkit'
import qs from 'qs'

/**Axios Wrapper...nothing fancy here*/
import CycloneAPIInstance from 'common/cyclone/api/api.client'
import CycloneConfig from 'config/base'

/** Main API Server URL */
const API_URL = CycloneConfig.API_URL

const session = JSON.parse(localStorage.getItem('authentication'))

/** Define Initial State */
export const initialState = session
  ? {
      hasErrors: false,
      session: session,
    }
  : {
      hasErrors: false,
      session: [],
    }

/** Define Slice  */
const authenticationSlice = createSlice({
  name: 'authentication',
  initialState,
  reducers: {
    authenticateUser: (state) => {
      state.hasErrors = false
    },
    authenticateUserSuccess: (state, { payload }) => {
      state.hasErrors = false
      state.session = payload
      console.log(state.session)
    },
    authenticateUserFailure: (state, { payload }) => {
      state.hasErrors = true
      state.session = payload
    },
    deauthenticateUser: (state) => {
      state.session = []
    },
  },
})

export const {
  authenticateUser,
  authenticateUserSuccess,
  authenticateUserFailure,
  deauthenticateUser,
} = authenticationSlice.actions

export const authenticationSelector = (state) => state.authentication

export default authenticationSlice.reducer

export function authenticateByLogin(user_name, user_password) {
  let requestBody = {
    user_name: user_name,
    user_password: user_password,
  }

  let config = {
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
    },
  }

  return async (dispatch) => {
    dispatch(authenticateUser())

    try {
      const response = await CycloneAPIInstance.post(
        API_URL + 'auth/login',
        qs.stringify(requestBody),
        config
      )
      //console.log(response.data.content)
      localStorage.setItem('session', JSON.stringify(response.data.content))
      dispatch(authenticateUserSuccess(response.data.content))
    } catch (error) {
      //console.log(JSON.stringify(error.response.data))
      dispatch(authenticateUserFailure(error.response.data))
    }
  }
}

export function deauthenticateByLogout() {
  return async (dispatch) => {
    dispatch(deauthenticateUser())
    localStorage.removeItem('session')
  }
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-10-04 22:22:27

尝试设置hasError更改时的消息

代码语言:javascript
复制
useEffect(()=> {
  if(hasErrors) {
   setErrorMessage(session.error.message)
  }
}, [hasErrors]);
票数 1
EN

Stack Overflow用户

发布于 2020-10-04 22:19:14

这是相当多的代码,所以我只是跳过来解决这个问题,而不是把所有的东西都拆开。我最好的猜测是这一部分:

代码语言:javascript
复制
dispatch(authenticateByLogin(username, password))
        .then(() => {
          setLoading(false)
          if (hasErrors) {
            setErrorMessage(session.error.message)
          } else {
            //props.history.push('/profile')
            // window.location.reload()
          }
        })
        .catch(() => {
          setLoading(false)
        })

在这里,您执行异步身份验证,然后根据"hasError“执行操作。这个"hasError“来自一个钩子。我们(至少我)不清楚这是如何管理的。问题是,当你在then-block中检查它的时候,你不能100%确定hasError是真正值得信任的。钩子可能会在下一次渲染之后运行,这解释了为什么您看到的是前一个状态,而不是实际的状态。

最好的猜测是使用来自异步调用的响应,因为应该有一个响应authenticate.then(() => if(response.hasError) ...)通过此检查,您可以设置自己的错误状态,并且您的组件应该是最新的

如果这修复了您的错误,请让我知道。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64195393

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档