我试图围绕redux,react-redux和redux-form进行包装.
我已经设置了一个商店并添加了redux-form的reducer.我的表单组件如下所示:
登录表格
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 () } } LoginForm.propTypes = { fields: PropTypes.object.isRequired, handleSubmit: PropTypes.func.isRequired, submitting: PropTypes.bool.isRequired } export default reduxForm({ form: 'login', fields })(LoginForm)
这可以按预期工作,在redux DevTools中,我可以看到如何在表单输入上更新商店,以及在提交表单时login
动作创建者调度登录操作.
我将redux-thunk中间件添加到商店并设置用于登录的操作创建者,如异步操作的redux文档中所述:
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))) } }
同样,在redux DevTools中,我可以看到它按预期工作.当dispatch(login(formData))
被称为onSubmit
在LoginForm的,第一个LOGIN_REQUEST
动作是出动,其次是LOGIN_SUCCESS
或LOGIN_FAILURE
.LOGIN_REQUEST
将一个属性添加state.auth.pending = true
到店,LOGIN_SUCCESS
并LOGIN_FAILURE
会删除该属性.(我知道这可能是我使用重新选择的东西,但是现在我想保持简单.
现在,在redux-form文档中,我读到我可以返回一个promise onSubmit
以更新表单状态(submitting
,error
).但我不确定这样做的正确方法是什么.dispatch(login(formData))
回报undefined
.
我可以state.auth.pending
在商店中用一个变量来交换标志,例如请求state.auth.status
的值,成功和失败(再次,我可能会使用重新选择或类似的东西).
然后我可以订阅商店onSubmit
并处理这样的更改state.auth.status
:
// ... 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 } // ...
但是,这个解决方案感觉并不好,我不确定当应用程序增长并且可能从其他来源发送更多操作时它是否总是按预期工作.
我看到的另一个解决方案是将api调用(返回一个promise)移动到onSubmit
,但我想将它与React组件分开.
有什么建议吗?
dispatch(login(formData))
回报undefined
基于redux-thunk的文档:
内部函数的任何返回值都将作为其
dispatch
自身的返回值.
所以,你想要的东西
// 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; } }