Sto cercando di avvolgere la mia testa intorno a redux, react-redux e redux-form.react/redux-form: come restituire la promessa da onSubmit?
Ho installato un negozio e aggiunto il riduttore da redux-form. La mia componente forma simile a questa:
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)
Questo funziona come previsto, in redux DevTools posso vedere come il negozio viene aggiornato su input forma e su presentando il modulo del login
azione creatore invia l' azioni di accesso.
ho aggiunto il redux-thunk middleware al negozio e configurazione creatore azione (s) per l'accesso come descritto nelle 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)))
}
}
Ancora, in DevTools Redux Vedo che funziona come previsto. Quando viene chiamato in onSubmit
nel LoginForm, viene inviata prima l'azione LOGIN_REQUEST
seguita da LOGIN_SUCCESS
o LOGIN_FAILURE
. LOGIN_REQUEST
aggiungerà una proprietà state.auth.pending = true
al negozio, LOGIN_SUCCESS
e LOGIN_FAILURE
rimuoverà questa proprietà. (So che questo potrebbe essere qualcosa da usare reselect per, ma per ora voglio mantenerlo semplice
Ora, nei documenti redux-form ho letto che posso restituire una promessa da onSubmit
per aggiornare lo stato del modulo (submitting
, error
). Ma non sono sicuro di quello che è il modo corretto per farlo. dispatch(login(formData))
rendimenti undefined
.
ho potuto scambiare la bandiera state.auth.pending
nel negozio con una variabile come state.auth.status
con i valori richiesti, successo e errore (e di nuovo, Probabilmente potrei usare la riselezione o qualcosa di simile per questo).
ho potuto quindi abbonarsi al negozio in onSubmit
e gestire le modifiche al state.auth.status
in questo modo:
// ...
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
}
// ...
Tuttavia, questa soluzione non si sente bene e non sono sicuro se sarà sempre funzionare come previsto quando l'app cresce e altre azioni potrebbero essere inviate da altre fonti.
Un'altra soluzione che ho visto è spostare la chiamata api (che restituisce una promessa) a onSubmit
, ma vorrei mantenerla separata dal componente React.
Qualche consiglio in merito?
Nizza, grazie! Sapevo che doveva essere più facile ... :) –
È possibile restituire una promessa basata sugli errori apiClient? – gkkirsch