#javascript #reactjs #redux #react-router #redux-saga
Вопрос:
Я пытаюсь перенаправить пользователя после успешного входа в систему, но изменение состояния в saga вызывает бесконечный цикл.
компонент
В моем компоненте я использую useSelector для прослушивания изменений в сеансе isValidSession из магазина. Если сеанс isValidSession изменится на true, я хочу перенаправить пользователя на другую страницу. Однако при изменении сеанса isValidSession мой компонент продолжает выполнять рендеринг в бесконечном цикле.
import { Link, useLocation } from 'react-router-dom' import { Redirect } from 'react-router' import MainLayout from '../../../layouts/MainLayout' import { Typography, Alert, Row, Col, Divider } from 'antd' import LoginForm from './LoginForm' import { useDispatch, useSelector } from 'react-redux' import * as loginActions from './Login.action' const { Title } = Typography export default function Login() { const dispatch = useDispatch() const { isValidSession, error } = useSelector((state) =gt; state.login) const location = useLocation() let { from } = location.state || { from: { pathname: '/templates' } } const handleLogin = ({ email, password }) =gt; { dispatch(loginActions.authenticate({ email, password })) } const getAPIError = (error) =gt; error.status == 401 ? 'Invalid username or password' : 'Something went wrong' if (isValidSession) return lt;Redirect push to={from.pathname} /gt; return ( lt;MainLayoutgt; lt;Row align='stretch' className='vh-100'gt; lt;Col xs={24} md={12} lg={10} xl={8} xxl={6} className='bg--white'gt; lt;div className='d-flex align-items-center h-100 p-5'gt; lt;div id='login' className='w-100'gt; lt;Title level={3}gt;Welcome Back!lt;/Titlegt; {/* ERROR MESSAGE */} {error ? ( lt;Alert message={getAPIError(error)} showIcon type='error' className='mb-2' /gt; ) : ( '' )} {/* FORM */} lt;LoginForm onFinish={handleLogin} /gt; lt;Divider /gt; {/* ADDITIONAL LINKS */} lt;div className='text-center'gt; lt;pgt; Don't have an account yet?{' '} lt;Link to={{ pathname: '/register', state: { from: location } }} gt; Sign up lt;/Linkgt; lt;/pgt; lt;Link to={{ pathname: '/auth/recover-password', state: { from: location }, }} gt; Forgot your password? lt;/Linkgt; lt;/divgt; lt;/divgt; lt;/divgt; lt;/Colgt; lt;/Rowgt; lt;/MainLayoutgt; ) }
редуктор
В моем редукторе, для типов действий.LOGIN_SUCCESS, я делаю сеанс isValidSession равным true.
const loginReducer = (state = initialState, action) =gt; { switch (action.type) { case types.LOGIN_REQUESTING: { return { ...state, submitted: false, } } case types.LOGIN_SUCCESS: { return { ...state, submitted: true, successful: true, isValidSession: true, } } case types.LOGIN_ERROR: { const { error } = action return { ...state, error, submitted: false, successful: false, isValidSession: false, } } case types.UPDATE_LOGIN_CREDENTIAL: { const { login } = action return { ...state, login: { ...state.login, ...login, }, } } case types.IS_LOGGINGIN: { const { isLoggingIn } = action return { ...state, isLoggingIn, } } default: return { ...state, } } }
saga
In my saga code, you can see that I am doing yield put({ type: types.LOGIN_SUCCESS }) to change isValidSession to true.
function* authenticateSage(payload) { try { alert('authenticateSage') const response = yield call(authService.login, payload.login) const { profile, account } = response yield put({ type: types.LOGIN_SUCCESS }) } catch (error) { yield put({ type: types.LOGIN_ERROR, error: { status: error.status, message: error.data?.message }, }) } } export default function* watchAuthentication() { yield takeLatest(types.LOGIN_REQUESTING, authenticateSage) }