为什么 useReducer 钩子不更新状态?
Why is useReducer hook not updating state?
我正在研究 React 中的 login/register 个组件,我正在使用 useContext 和 useReducer 挂钩来管理状态。这是我第一次尝试这种方式,我不确定为什么状态没有改变。以下是登录组件的文件。我已经展示了我在哪里登录控制台以及结果是什么。
这是api:
export const login = ({ email, password }) => {
console.log(email, password);
// jennifer@jennifer.com 12345678
return fetch(`${DEV_AUTH_URL}/signin`, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
email,
password,
}),
})
.then((res) => {
return res.ok
? res.json()
: res.json().then(err => PromiseRejectionEvent.reject(err));
})
.then(data => data);
};
这是状态管理器:
const AuthState = (props) => {
const initialState = {
token: null,
isAuth: false,
errorMsg: null,
user: {},
};
const [state, dispatch] = useReducer(AuthReducer, initialState);
const history = useHistory();
const handleLogin = (formData) => {
login(formData)
.then((res) => {
console.log(res);
// {token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7I…zk3fQ.Qx9zDeXBecToIEScCTDXzkBiTnATHab4cnyg0aSMdLE"}
res && res.token
? dispatch({ type: LOGIN_SUCCESS, payload: res })
: dispatch({ type: LOGIN_FAIL, payload: res });
})
.then(() => {
closeAllPopups();
console.log('jwt: ', localStorage.getItem('jwt'));
// {token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7I…zk3fQ.Qx9zDeXBecToIEScCTDXzkBiTnATHab4cnyg0aSMdLE"}
console.log('token: ', state.token);
// token: null
console.log('isAuth: ', state.isAuth);
// isAuth: false
history.push('/');
})
.catch((err) => dispatch({ type: LOGIN_FAIL, payload: err.toString() }));
};
这是减速器中的内容:
import {
LOGIN_SUCCESS,
LOGIN_FAIL,
} from '../types';
export default (state, action) => {
switch (action.type) {
case LOGIN_SUCCESS:
localStorage.setItem('jwt', action.payload.token);
return {
...state,
token: action.payload.token, // this is not changing state
isAuth: true, // this is also not changing state
};
case LOGIN_FAIL:
return {
...state,
token: null,
user: {},
isAuth: false,
errorMsg: action.payload,
};
default:
return state;
}
};
问题
有点不清楚您真正想要的逻辑流程是什么,但是 React 状态更新是异步的,并且调用 handleLogin
回调的渲染周期中的状态包含在生命周期的回调范围内该功能的。仅仅因为 React 状态更新是异步的并不意味着它们可以在任何一个上等待。
解决方案
据我所知,您想调用 login
,并在登录成功后分派一个操作、关闭弹出窗口、记录一些值,然后导航到主页。除了记录更新状态之外,这都可以在第一个 thenable
.
中完成
const handleLogin = (formData) => {
login(formData)
.then((res) => {
console.log(res);
res?.token
? dispatch({ type: LOGIN_SUCCESS, payload: res })
: dispatch({ type: LOGIN_FAIL, payload: res });
closeAllPopups();
history.push('/');
})
.catch((err) => {
dispatch({ type: LOGIN_FAIL, payload: err.toString() });
});
};
使用 useEffect
挂钩记录任何状态更新。
useEffect(() => {
console.log('jwt: ', localStorage.getItem('jwt'));
console.log('token: ', state.token);
console.log('isAuth: ', state.isAuth);
}, [state]);
我正在研究 React 中的 login/register 个组件,我正在使用 useContext 和 useReducer 挂钩来管理状态。这是我第一次尝试这种方式,我不确定为什么状态没有改变。以下是登录组件的文件。我已经展示了我在哪里登录控制台以及结果是什么。
这是api:
export const login = ({ email, password }) => {
console.log(email, password);
// jennifer@jennifer.com 12345678
return fetch(`${DEV_AUTH_URL}/signin`, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
email,
password,
}),
})
.then((res) => {
return res.ok
? res.json()
: res.json().then(err => PromiseRejectionEvent.reject(err));
})
.then(data => data);
};
这是状态管理器:
const AuthState = (props) => {
const initialState = {
token: null,
isAuth: false,
errorMsg: null,
user: {},
};
const [state, dispatch] = useReducer(AuthReducer, initialState);
const history = useHistory();
const handleLogin = (formData) => {
login(formData)
.then((res) => {
console.log(res);
// {token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7I…zk3fQ.Qx9zDeXBecToIEScCTDXzkBiTnATHab4cnyg0aSMdLE"}
res && res.token
? dispatch({ type: LOGIN_SUCCESS, payload: res })
: dispatch({ type: LOGIN_FAIL, payload: res });
})
.then(() => {
closeAllPopups();
console.log('jwt: ', localStorage.getItem('jwt'));
// {token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7I…zk3fQ.Qx9zDeXBecToIEScCTDXzkBiTnATHab4cnyg0aSMdLE"}
console.log('token: ', state.token);
// token: null
console.log('isAuth: ', state.isAuth);
// isAuth: false
history.push('/');
})
.catch((err) => dispatch({ type: LOGIN_FAIL, payload: err.toString() }));
};
这是减速器中的内容:
import {
LOGIN_SUCCESS,
LOGIN_FAIL,
} from '../types';
export default (state, action) => {
switch (action.type) {
case LOGIN_SUCCESS:
localStorage.setItem('jwt', action.payload.token);
return {
...state,
token: action.payload.token, // this is not changing state
isAuth: true, // this is also not changing state
};
case LOGIN_FAIL:
return {
...state,
token: null,
user: {},
isAuth: false,
errorMsg: action.payload,
};
default:
return state;
}
};
问题
有点不清楚您真正想要的逻辑流程是什么,但是 React 状态更新是异步的,并且调用 handleLogin
回调的渲染周期中的状态包含在生命周期的回调范围内该功能的。仅仅因为 React 状态更新是异步的并不意味着它们可以在任何一个上等待。
解决方案
据我所知,您想调用 login
,并在登录成功后分派一个操作、关闭弹出窗口、记录一些值,然后导航到主页。除了记录更新状态之外,这都可以在第一个 thenable
.
const handleLogin = (formData) => {
login(formData)
.then((res) => {
console.log(res);
res?.token
? dispatch({ type: LOGIN_SUCCESS, payload: res })
: dispatch({ type: LOGIN_FAIL, payload: res });
closeAllPopups();
history.push('/');
})
.catch((err) => {
dispatch({ type: LOGIN_FAIL, payload: err.toString() });
});
};
使用 useEffect
挂钩记录任何状态更新。
useEffect(() => {
console.log('jwt: ', localStorage.getItem('jwt'));
console.log('token: ', state.token);
console.log('isAuth: ', state.isAuth);
}, [state]);