调用后端后,动作函数总是在 React 中返回相同的 reducer 类型
Action function always returning same reducer type in React after calling backend
所以我正处于完成我的 2FA 方法的最后一步,现在我需要检测用户是否启用了他的方法,为了实现这一点,我创建了一个函数 return如下:
if (!user.twoFactorTokenEnabled) {
// If user has not enabled twoFactorAuthentication, then
// let him proceed and log in into his account
sendTokenResponse(user, 200, req, res)
} else {
// Otherwise, just return the following fields:
// username, isEmailConfirmed and twoFactorTokenEnabled
res.status(200).json({ success: true, data: user })
}
该功能位于后端,目前运行良好,至少我是这么认为的。
话虽如此,我每次提交表单时都会进入我的登录组件并触发 login
函数:
const [TFAEEnabled, setTFAEnabled] = useState(false)
login(loginData, history)
.then((result) => {
// If twoFactorTokenEnabled is found to be true
// then call this function and set it to true and then
// display and extra field to enter
// a google authenticator code
setTFAEnabled(result.payload.data.twoFactorTokenEnabled)
})
.catch((err) => {
setTFAEnabled(false)
setError(true)
})
// This is found within my returned component.
{
TFAEEnabled && (
<Form.Control
type="text"
placeholder="Authenticator Code"
aria-label="2FA-CODE"
aria-describedby="2FA-CODE-text"
autoComplete="2FA-CODE"
name="2FA-CODE"
id="2FA-CODE"
minLength="6"
required
// onChange={handleChange('2FA-CODE')}
value="2FA Code"
/>
)
}
在上面的代码中,我试图展示我正在尝试完成的是“如果 X 为真,则只显示此组件”。然而,该函数根本无法正常工作,因为它总是以调用第一个 reducer 类型结束,这是登录函数:
export const login = (loginData, history) => async (dispatch) => {
try {
const res = await api.post(`/auth/login`, loginData)
if (!res.data.twoFactorTokenEnabled) {
// if twoFactorTokenEnabled === false then let
// the user log in into his account normally
// without requiring a token provided by Y
// authenticator app
dispatch({
type: LOGIN_SUCCESS,
payload: res.data,
})
// Dispatch the rest of the user data
dispatch(loadUser())
// and let him in
history.push('/timeline')
} else {
// otherwise, if twoFactorTokenEnabled === true
// return the previously mentioned data given by
// the backend: username, isEmailConfirmed and
// twoFactorTokenEnabled
return dispatch({
type: LOGIN_SUCCESS_REQUEST,
payload: res.data,
})
}
} catch (err) {
const error = err.response.data.message
const errors = err?.response?.data?.errors
if (error) {
dispatch(setAlert(error, 'danger'))
}
if (errors) {
errors.forEach((error) => dispatch(setAlert(error.msg, 'danger')))
}
dispatch({
type: LOGIN_FAIL,
payload: { msg: err.response?.statusText, status: err.response?.status },
})
}
}
后端工作得很好!它 return 是它应该 return 的数据,我认为问题出在我的 reducer 上:
// if twoFactorTokenEnabled === true
// call this reducer which should only return
// the 4 fields given by the backend
case LOGIN_SUCCESS_REQUEST:
return {
...state,
// ...payload,
isAuthenticated: false,
isTFAEnabled: payload,
loading: false
};
// Otherwise let the user in and return everything
case LOGIN_SUCCESS:
return {
...state,
...payload,
isAuthenticated: true,
loading: false
};
希望这足以解释,否则请随时索取更多信息。
谢谢!
我认为你正在使用 Redux-thunk,你需要调度你的动作函数。
然后可以从 Redux 商店中选择 TFAEEnabled。
const TFAEEnabled = useSelector(state => state.isAuthenticated);
const dispatch = useDispatch();
dispatch(login(loginData, history));
我实际上发现我不在 return 根据后端发送的数据,我不得不在 if 语句中 return 第二个 'data' :
const res = await api.post(`/auth/login`, loginData);
if (res.data.data) {
history.push(`/two-fa-validate/${res.data.data._id}`);
return dispatch({
type: LOGIN_SUCCESS_REQUEST,
payload: res.data
});
}
dispatch({
type: LOGIN_SUCCESS,
payload: res.data
});
dispatch(loadUser());
history.push('/timeline');
所以我正处于完成我的 2FA 方法的最后一步,现在我需要检测用户是否启用了他的方法,为了实现这一点,我创建了一个函数 return如下:
if (!user.twoFactorTokenEnabled) {
// If user has not enabled twoFactorAuthentication, then
// let him proceed and log in into his account
sendTokenResponse(user, 200, req, res)
} else {
// Otherwise, just return the following fields:
// username, isEmailConfirmed and twoFactorTokenEnabled
res.status(200).json({ success: true, data: user })
}
该功能位于后端,目前运行良好,至少我是这么认为的。
话虽如此,我每次提交表单时都会进入我的登录组件并触发 login
函数:
const [TFAEEnabled, setTFAEnabled] = useState(false)
login(loginData, history)
.then((result) => {
// If twoFactorTokenEnabled is found to be true
// then call this function and set it to true and then
// display and extra field to enter
// a google authenticator code
setTFAEnabled(result.payload.data.twoFactorTokenEnabled)
})
.catch((err) => {
setTFAEnabled(false)
setError(true)
})
// This is found within my returned component.
{
TFAEEnabled && (
<Form.Control
type="text"
placeholder="Authenticator Code"
aria-label="2FA-CODE"
aria-describedby="2FA-CODE-text"
autoComplete="2FA-CODE"
name="2FA-CODE"
id="2FA-CODE"
minLength="6"
required
// onChange={handleChange('2FA-CODE')}
value="2FA Code"
/>
)
}
在上面的代码中,我试图展示我正在尝试完成的是“如果 X 为真,则只显示此组件”。然而,该函数根本无法正常工作,因为它总是以调用第一个 reducer 类型结束,这是登录函数:
export const login = (loginData, history) => async (dispatch) => {
try {
const res = await api.post(`/auth/login`, loginData)
if (!res.data.twoFactorTokenEnabled) {
// if twoFactorTokenEnabled === false then let
// the user log in into his account normally
// without requiring a token provided by Y
// authenticator app
dispatch({
type: LOGIN_SUCCESS,
payload: res.data,
})
// Dispatch the rest of the user data
dispatch(loadUser())
// and let him in
history.push('/timeline')
} else {
// otherwise, if twoFactorTokenEnabled === true
// return the previously mentioned data given by
// the backend: username, isEmailConfirmed and
// twoFactorTokenEnabled
return dispatch({
type: LOGIN_SUCCESS_REQUEST,
payload: res.data,
})
}
} catch (err) {
const error = err.response.data.message
const errors = err?.response?.data?.errors
if (error) {
dispatch(setAlert(error, 'danger'))
}
if (errors) {
errors.forEach((error) => dispatch(setAlert(error.msg, 'danger')))
}
dispatch({
type: LOGIN_FAIL,
payload: { msg: err.response?.statusText, status: err.response?.status },
})
}
}
后端工作得很好!它 return 是它应该 return 的数据,我认为问题出在我的 reducer 上:
// if twoFactorTokenEnabled === true
// call this reducer which should only return
// the 4 fields given by the backend
case LOGIN_SUCCESS_REQUEST:
return {
...state,
// ...payload,
isAuthenticated: false,
isTFAEnabled: payload,
loading: false
};
// Otherwise let the user in and return everything
case LOGIN_SUCCESS:
return {
...state,
...payload,
isAuthenticated: true,
loading: false
};
希望这足以解释,否则请随时索取更多信息。
谢谢!
我认为你正在使用 Redux-thunk,你需要调度你的动作函数。 然后可以从 Redux 商店中选择 TFAEEnabled。
const TFAEEnabled = useSelector(state => state.isAuthenticated);
const dispatch = useDispatch();
dispatch(login(loginData, history));
我实际上发现我不在 return 根据后端发送的数据,我不得不在 if 语句中 return 第二个 'data' :
const res = await api.post(`/auth/login`, loginData);
if (res.data.data) {
history.push(`/two-fa-validate/${res.data.data._id}`);
return dispatch({
type: LOGIN_SUCCESS_REQUEST,
payload: res.data
});
}
dispatch({
type: LOGIN_SUCCESS,
payload: res.data
});
dispatch(loadUser());
history.push('/timeline');