redux 、 react-redux 、 redux-form に頭を包み込もうとしています。
ストアをセットアップし、redux-formからレデューサーを追加しました。私のフォームコンポーネントは次のようになります。
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)
_
これは期待どおりに機能します。 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では、これが期待どおりに機能することがわかります。 LoginFormのonSubmit
でdispatch(login(formData))
が呼び出されると、最初に_LOGIN_REQUEST
_アクションがディスパッチされ、次に_LOGIN_SUCCESS
_または_LOGIN_FAILURE
_がディスパッチされます。 _LOGIN_REQUEST
_はプロパティ_state.auth.pending = true
_をストアに追加し、_LOGIN_SUCCESS
_と_LOGIN_FAILURE
_はこのプロパティを削除します。 (私はこれが私に何かを使うかもしれないことを知っています 再選択 のために、しかし今のところ私はそれを単純に保ちたいです。
さて、redux-formのドキュメントで、onSubmit
からpromiseを返して、フォームの状態(submitting
、error
)を更新できることを読みました。しかし、これを行う正しい方法が何であるかはわかりません。 dispatch(login(formData))
はundefined
を返します。
ストア内の_state.auth.pending
_フラグを、値requested、success、およびfailureの_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;
}
}