我通读了此解决方案here。但是我不知道如果不使用useEffect
钩子怎么办。这个问题的重点将放在Login.js
文件中。
这是我现在的代码:-
AuthState.js
:-import React, { useContext, useReducer } from 'react'
import { AuthContext } from './AuthContext'
import AuthReducer from './AuthReducer'
export const useAuth = () => {
const { state, dispatch } = useContext(AuthContext)
return [state, dispatch]
}
export const AuthState = ({ children }) => {
const initialState = {
uid: '',
authenticated: false,
isactive: false,
loading: true,
error: false,
message: ''
}
const [state, dispatch] = useReducer(AuthReducer, initialState)
return (
<AuthContext.Provider value={{
state: state,
dispatch: dispatch
}}>
{children}
</AuthContext.Provider>
)
}
AuthAction.js
(所有与身份验证相关的操作已在此处完成)import axios from 'axios'
// Json Header
const config = {
headers: {
'Content-Type': 'application/json'
}
}
// Set Loading
export const setLoading = (dispatch) => dispatch({ type: 'SET_LOADING', payload: false })
// Set Error
export const setError = (dispatch, error) => dispatch({ type: 'SET_ERROR', payload: { error: error.status, message: error.message } })
// User Login
export const isLogin = async(dispatch, credentials) => {
setLoading(dispatch)
await axios.post('/api/auth', credentials, config)
.then(res => {
console.log(res.data.data) // data do show up, but not updated into the state
dispatch({
type: 'GET_RESPONSE_LOGIN',
payload: res.data.data
})
}).catch(error => {
console.log(error.response.data.error) // do show up, but not updated into the state
dispatch({
type: 'SET_ERROR',
payload: {
error: true,
message: error.response.data.error
}
})
})
}
// User Logout
export const isLogout = async(dispatch, uid) => {
setLoading(dispatch)
await axios.post('/api/auth/logout', { uid: uid }, config)
.then(res => {
dispatch({
type: 'GET_RESPONSE_LOGOUT',
payload: res.data.data
})
}).catch(error => {
dispatch({
type: 'SET_ERROR',
payload: {
error: true,
message: error.response.data.error
}
})
})
}
// Check user isActive
export const isActive = async(dispatch, uid) => {
setLoading(dispatch)
await axios.post('/api/auth/isactive', { uid: uid }, config)
.then(res => {
dispatch({
type: 'GET_RESPONSE_ISACTIVE',
payload: res.data.data
})
}).catch(error => {
dispatch({
type: 'SET_INACTIVE',
payload: {
error: true,
message: error.response.data.error
}
})
})
}
AuthReducer.js
:-export default (state, action) => {
switch(action.type) {
case 'GET_RESPONSE_LOGIN':
return {
...state,
uid: action.payload.uid,
authenticated: true,
isactive: true,
error: false,
}
case 'GET_RESPONSE_LOGOUT':
return {
...state,
uid: '',
authenticated: false,
isactive: false,
error: false,
}
case 'GET_RESPONSE_ISACTIVE':
return {
...state
}
case 'SET_INACTIVE':
return {
...state,
uid: '',
authenticated: false,
isactive: false,
error: action.payload.error,
message: action.payload.message
}
case 'SET_ERROR':
return {
...state,
error: action.payload.error,
message: action.payload.message
}
case 'SET_LOADING':
return {
...state,
loading: action.payload
}
default:
return state
}
}
Login.js
(登录页面)import React, { useState } from 'react'
import { isLogin, setError } from '../../contexts/Auth/AuthAction'
import { useAuth } from '../../contexts/Auth/AuthState'
import { Button } from '../Button'
import { FaTimes } from 'react-icons/fa'
import { Error } from './Error'
import './Section.css'
export const Section = () => {
const [authState, authDispatch] = useAuth()
const { uid, authenticated, error, message } = authState
// section bg color
const [lightBg] = useState(true)
// page specific states & functions
const [username, setUsername] = useState('')
const [password, setPassword] = useState('')
// handle login function
const handleLogin = async(e) => {
e.preventDefault()
await isLogin(authDispatch, { uid: uid, email: username, password: password })
// empty out placeholders
setUsername('')
setPassword('')
// Export this in new component
// if authenticated, then go to dashboard
if(authenticated) return history.push('/pfv4-admin/dashboard')
}
return (
<>
<div className={lightBg ? 'login__section' : 'login__section darkBg'}>
<div className="login__wrapper">
{/* Export this in new component */}
{error && (
<div className="error__container">
<FaTimes size={20} className="error__btn"
onClick={() => setError(authDispatch, {error: false, message: ''})}
/>
<p className="error__message message__break">{message}</p>
</div>
)}
<div className="inputs__container">
<form className="input__form"
onSubmit={(e) => {
handleLogin(e)
}}
>
<div className="form__group">
<label className={lightBg ? 'form__label' : 'form__label darkLabel'}>Username</label>
<input type="email"
value={username}
onChange={(e) => setUsername(e.target.value)}
className={lightBg ? 'form__inputfield' : 'form__inputfield darkInputfield'}
required
/>
</div>
<div className="form__group">
<label className={lightBg ? 'form__label' : 'form__label darkLabel'}>Password</label>
<input type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
className={lightBg ? 'form__inputfield' : 'form__inputfield darkInputfield'}
required
/>
</div>
{lightBg ? (
<Button buttonSize="btn--wide">Login</Button>
) : (
<Button buttonSize="btn--wide" buttonColor="accents">Login</Button>
)}
</form>
</div>
</div>
</div>
</>
)
}
使用上面的代码。我遇到了Can't perform react state update on an unmounted component...
错误。就像我之前说的那样,因为我使用Context APi
。我无法添加let mounted = true
和清理功能return () => {mounted = false}
。
相反,由于我加入了Context API
。我刚刚调用了函数isLogin
来处理用户向服务器输入的post
中的credentials
。
但是我确实找到了解决方案或没有。通过导出error
和authenticated
状态检查(如下所示):-
Login.js
:-import React, { useState } from 'react'
import { isLogin } from '../../contexts/Auth/AuthAction'
import { useAuth } from '../../contexts/Auth/AuthState'
import { Button } from '../Button'
import { Error } from './Error'
import './Section.css'
export const Section = () => {
const [authState, authDispatch] = useAuth()
const { uid } = authState
// section bg color
const [lightBg] = useState(true)
// page specific states & functions
const [username, setUsername] = useState('')
const [password, setPassword] = useState('')
// handle login function
const handleLogin = async(e) => {
e.preventDefault()
await isLogin(authDispatch, { uid: uid, email: username, password: password })
// empty out placeholders
setUsername('')
setPassword('')
}
return (
<>
<div className={lightBg ? 'login__section' : 'login__section darkBg'}>
<div className="login__wrapper">
<Error />
<div className="inputs__container">
<form className="input__form"
onSubmit={(e) => {
handleLogin(e)
}}
>
<div className="form__group">
<label className={lightBg ? 'form__label' : 'form__label darkLabel'}>Username</label>
<input type="email"
value={username}
onChange={(e) => setUsername(e.target.value)}
className={lightBg ? 'form__inputfield' : 'form__inputfield darkInputfield'}
required
/>
</div>
<div className="form__group">
<label className={lightBg ? 'form__label' : 'form__label darkLabel'}>Password</label>
<input type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
className={lightBg ? 'form__inputfield' : 'form__inputfield darkInputfield'}
required
/>
</div>
{lightBg ? (
<Button buttonSize="btn--wide">Login</Button>
) : (
<Button buttonSize="btn--wide" buttonColor="accents">Login</Button>
)}
</form>
</div>
</div>
</div>
</>
)
}
Error.js
(作为组件导出的那个):-import React, { useEffect } from 'react'
import { FaTimes } from 'react-icons/fa'
import { useHistory } from 'react-router-dom'
import { setError } from '../../contexts/Auth/AuthAction'
import { useAuth } from '../../contexts/Auth/AuthState'
export const Error = () => {
const [authState, authDispatch] = useAuth()
const { authenticated, error, message } = authState
// page specific states & functions
const history = useHistory()
useEffect(() => {
if(authenticated) return history.push('/pfv4-admin/dashboard')
}, [authenticated])
return (
<>
{error && (
<div className="error__container">
<FaTimes size={20} className="error__btn"
onClick={() => setError(authDispatch, {error: false, message: ''})}
/>
<p className="error__message message__break">{message}</p>
</div>
)}
</>
)
}
有了这些更改,我就能克服这个问题。 但是任何人都可以与我分享我该怎么做,以确保不会再次发生这种错误?当然要使用Context API。
就像我之前说的,我确实认为在某些情况下我可以使用let isMounted = true
并执行清理功能。但是我不知道是否可以在这里实现这种方法。