Я искал элегантный (и правильный) способ обработки входа в приложение Redux. В настоящее время пользователь обращается к компоненту/контейнеру входа, где он видит форму с именем пользователя и паролем. Затем, когда он нажимает на отправку, я вызываю функцию входа в систему async и, когда обещание выполняется, я отправляю loginSuccess, а также вызов replacePath. Ниже приведен некоторый псевдокод:
submit(e) {
login(username, password)
.then(function (user) {
dispatch(loginSuccess(user));
dispatch(replacePath('/');
});
}
Это работает, но я не уверен, что это лучшая практика. У кого-нибудь есть лучшие реализации?
Его обычно считается плохой практикой, чтобы вызвать отправку внутри компонента, если только контейнер верхнего уровня не подключен к хранилищу.
Я бы рекомендовал следовать примерам, которые Дэн Абрамов дает в документах, в первую очередь примере асинхронного Reddit. Посмотрите, как он обрабатывает промежуточный запрос с помощью posts.isFetching
.
Поскольку я знаю, что StackOverflow не любит ссылки, здесь упрощенный пример (в ES6):
Это действия:
// Actions
import fetch from 'isomorphic-fetch';
import * as types from '../constants/actionTypes.js';
var requestAuth = function() {
return {
type: type.REQUEST_AUTH
}
};
var authSuccess = function(response) {
return {
type: type.AUTH_SUCCESS,
response: response
}
};
var authFail = function(response) {
return {
type: type.AUTH_FAIL,
response: response
}
};
var authenticate = function(username, password) {
var fetchOptions = {
method: 'post',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({username: username, password: password})
};
var uri = '/api/path/to/your/login/backend';
return dispatch => {
dispatch(requestAuth);
return fetch(uri, fetchOptions)
.then(response => {
if (resopnse.status === 200) {
dispatch(authSuccess(response));
// Do any other login success work here
// like redirecting the user
} else {
dispatch(authFail(response));
}
}
}
};
Затем редуктор:
// Reducer
import { combineReducers } from 'redux';
import { REQUEST_AUTH, AUTH_SUCCESS, AUTH_FAIL } from '../actions/login';
function login(state = {
isAuthenticating: false,
isLoggedIn: false,
authenticationToken: '',
authError: null
....., // whatever other state vars you need
.....
}, action) {
switch(action.type) {
case REQUEST_AUTH:
return Object.assign({}, state, {
isAuthenticating: true
});
break;
case AUTH_SUCCESS:
return Object.assign({}, state, {
isAuthenticating: false,
isLoggedIn: true,
authenticationToken: action.response.token
});
break;
case AUTH_FAIL:
return Object.assign({}, state, {
isAuthenticating: false,
authError: action.response.error
});
break;
default:
return state;
}
}
И, наконец, компонентный метод
// Component Method
// authenticate() should be wrapped in bindActionCreators()
// and passed down as a prop
function handleSubmit(username, password) {
if (isValid(username) && isValid(password) {
authenticate(username, password);
}
}
tl; dr Ваш пользователь вводит свои учетные данные, которые должны быть частью состояния (не изображены здесь). OnClick в компоненте вызывает handleSubmit(), который отправляет authenticate(). Аутентификация отправляет requestAuth(), который обновляет состояние, чтобы показать вашему пользователю, что запрос обрабатывается (отображается счетчик загрузки или что-то еще). Как только вызов AJAX на бэкэнд возвращается с результатами проверки подлинности, вы отправляете authSuccess() или authFail() для обновления состояния и информируете пользователя о том, удалось ли их запрос или нет.
redux-thunk
состоит в том, чтобы эта логика происходила в создателе асинхронных действий, чтобы избежать привязки логики приложения к вашему пользовательскому интерфейсу.