Próbuję owijać głowę wokół redux, react-redux i redux-form.react/redux-form: jak zwrócić obietnicę z onSubmit?
Mam skonfigurować sklep i dodano reduktor z formularza redux. Mój składnik postać wygląda następująco:
LoginForm
import React, {Component, PropTypes} from 'react'
import { reduxForm } from 'redux-form'
import { login } from '../../actions/authActions'
const fields = ['username', 'password'];
class LoginForm extends Component {
onSubmit (formData, dispatch) {
dispatch(login(formData))
}
render() {
const {
fields: { username, password },
handleSubmit,
submitting
} = this.props;
return (
<form onSubmit={handleSubmit(this.onSubmit)}>
<input type="username" placeholder="Username/Email address" {...username} />
<input type="password" placeholder="Password" {...password} />
<input type="submit" disabled={submitting} value="Login" />
</form>
)
}
}
LoginForm.propTypes = {
fields: PropTypes.object.isRequired,
handleSubmit: PropTypes.func.isRequired,
submitting: PropTypes.bool.isRequired
}
export default reduxForm({
form: 'login',
fields
})(LoginForm)
To działa zgodnie z oczekiwaniami, w redux DevTools widzę, jak sklep jest aktualizowana na wejście formie i na wysłaniu formularza działanie twórca login
wywołuje akcje logowania.
I dodaje redux-thunk pośredniej do magazynu i konfiguracja twórcy działanie (S) do rejestrowania, w sposób opisany w redux docs for Async Actions:
authActions.js
import ApiClient from '../apiClient'
const apiClient = new ApiClient()
export const LOGIN_REQUEST = 'LOGIN_REQUEST'
function requestLogin(credentials) {
return {
type: LOGIN_REQUEST,
credentials
}
}
export const LOGIN_SUCCESS = 'LOGIN_SUCCESS'
function loginSuccess(authToken) {
return {
type: LOGIN_SUCCESS,
authToken
}
}
export const LOGIN_FAILURE = 'LOGIN_FAILURE'
function loginFailure(error) {
return {
type: LOGIN_FAILURE,
error
}
}
// thunk action creator returns a function
export function login(credentials) {
return dispatch => {
// update app state: requesting login
dispatch(requestLogin(credentials))
// try to log in
apiClient.login(credentials)
.then(authToken => dispatch(loginSuccess(authToken)))
.catch(error => dispatch(loginFailure(error)))
}
}
Ponownie w DevTools Redux Widzę, że działa zgodnie z oczekiwaniami. Kiedy dispatch(login(formData))
jest wywoływana w onSubmit
w LoginForm, najpierw wywoływana jest akcja LOGIN_REQUEST
, a następnie LOGIN_SUCCESS
lub LOGIN_FAILURE
. LOGIN_REQUEST
doda obiekt state.auth.pending = true
do sklepu, LOGIN_SUCCESS
i LOGIN_FAILURE
usunie tę właściwość. (Wiem, że to może być coś do wykorzystania dla reselect dla, ale na razie chcę, aby to było proste
Teraz, w dokumentach w formacie redux czytałem, że mogę zwrócić obietnicę z onSubmit
, aby zaktualizować stan formularza (submitting
, error
). Ale nie jestem pewien, co to jest poprawny sposób to zrobić. dispatch(login(formData))
powraca undefined
.
mógłbym wymieniać flagę state.auth.pending
w sklepie ze zmienną jak state.auth.status
z wartościami żądanych, sukces i niepowodzenie (i ponownie Prawdopodobnie mógłbym użyć ponownego wyboru lub czegoś podobnego do tego).
mogłem potem zapisać się do sklepu w onSubmit
i uchwyt zmiany state.auth.status
jak ten:
// ...
class LoginForm extends Component {
constructor (props) {
super(props)
this.onSubmit = this.onSubmit.bind(this)
}
onSubmit (formData, dispatch) {
const { store } = this.context
return new Promise((resolve, reject) => {
const unsubscribe = store.subscribe(() => {
const state = store.getState()
const status = state.auth.status
if (status === 'success' || status === 'failure') {
unsubscribe()
status === 'success' ? resolve() : reject(state.auth.error)
}
})
dispatch(login(formData))
}).bind(this)
}
// ...
}
// ...
LoginForm.contextTypes = {
store: PropTypes.object.isRequired
}
// ...
Jednak to rozwiązanie nie czują się dobrze i nie jestem pewien, czy to będzie zawsze działać zgodnie z oczekiwaniami kiedy aplikacja rośnie, a więcej działań może zostać wysłanych z innych źródeł.
Innym rozwiązaniem, które widziałem, jest przeniesienie wywołania api (które zwraca obietnicę) na onSubmit
, ale chciałbym zachować to oddzielenie od komponentu React.
Wszelkie porady na ten temat?
Nicea, dzięki! Wiedziałem, że musi być łatwiej ... :) –
Czy można zwrócić obietnicę na podstawie błędów apiClient? – gkkirsch