react / redux-form: comment rendre la promesse d'onSubmit?
je suis en train d'envelopper ma tête autour de redux,réagissent-redux et redux-forme.
j'ai configuré un magasin et j'ai ajouté le réducteur de redux-form. Ma composante de forme ressemble à ceci:
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)
Cela fonctionne comme prévu, dans redux DevTools je peux voir comment le magasin est mis à jour sur le formulaire d'entrée et sur la présentation de la forme login
action créateur dépêches les actions de connexion.
j'ai ajouté redux-thunk middleware au magasin et configurer le(s) créateur (s) d'action pour se connecter comme décrit dans le redux docs pour des Actions Asynchrones:
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)))
}
}
encore une fois, dans redux DevTools je peux voir que cela fonctionne comme prévu. Lorsque dispatch(login(formData))
est appelé onSubmit
dans le LoginForm, d'abord le LOGIN_REQUEST
action est distribué, suivi par LOGIN_SUCCESS
ou LOGIN_FAILURE
. LOGIN_REQUEST
ajouter une propriété state.auth.pending = true
pour le magasin, LOGIN_SUCCESS
et LOGIN_FAILURE
supprimer cette propriété. (Je sais que cela pourrait être quelque chose d'utiliser resélectionner pour, mais pour l'instant je veux rester simple.
maintenant, dans les docs redux-form j'ai lu que je peux retourner une promesse de onSubmit
mettre à jour l'état du formulaire (submitting
,error
). Mais je ne suis pas sûr quelle est la manière correcte de le faire. dispatch(login(formData))
retourne undefined
.
j'ai pu échanger le state.auth.pending
drapeau dans le magasin avec une variable comme state.auth.status
avec les valeurs demande,succès et échec (et encore une fois, je pourrais probablement utiliser reselect ou quelque chose de semblable pour cela).
je ne puis souscrire à la stocker dans onSubmit
et gérer les modifications apportées à state.auth.status
comme ceci:
// ...
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
}
// ...
cependant, cette solution ne se sent pas bien et je ne suis pas sûr qu'elle fonctionnera toujours comme prévu lorsque l'application se développe et que d'autres actions pourraient être lancées à partir d'autres sources.
une autre solution que j'ai vue est de déplacer l'appel api (qui renvoie une promesse) vers onSubmit
, mais je voudrais le garder séparé du composant React.
des conseils à ce sujet?
1 réponses
dispatch(login(formData))
retourneundefined
basé sur les docs pour redux-thunk:
toute valeur de retour de la fonction interne sera disponible comme valeur de retour de
dispatch
lui-même.
Donc, vous voulez quelque chose comme
// 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)))
return promiseOfSomeSort;
}
}