redux-form (1) - Simple Form Example
redux-form (2) - Synchronous Validation Example
redux-form (3) - Field-Level Validation Example
redux-form (4) - Submit Validation Example
redux-form (5) - Initialize From State
redux-form (6) - ユーザ登録
ReactでForm componentを作るときに、とても便利な**redux-form**の説明です。
redux-formの概説についてはまず以下の記事を参考にしてください。
redux-form (1) - Simple Form Example
Initialize From State
Initialize From State - Getting Started With redux-form
redux-formでは、decorated form component(wrapped component)のform stateを初期化するために、initialValuesを用います。initialValuesは、例えばサーバから取得した値を、React Redux の connect()を使って、mapStateToPropsでRedux state をinitialValues propに変換して、decorated form componentに渡すようにします。
initialValuesでformを初期化できるのは、デフォルトで1回のみです。
decorated form componentはreset() propを受け取りますが、reset()を実行することでformをinitialValuesに戻すことができます。
以下が、reducerとaction creatorのソースです。
// Quack! This is a duck. https://github.com/erikras/ducks-modular-redux
const LOAD = 'redux-form-examples/account/LOAD'
const reducer = (state = {}, action) => {
switch (action.type) {
case LOAD:
return {
data: action.data
}
default:
return state
}
}
/**
* Simulates data loaded into this reducer from somewhere
*/
export const load = data => ({ type: LOAD, data })
export default reducer
以下がredux-formのサンプルです。ポイントの説明を下にまとめてあります。
import React from 'react'
import { connect } from 'react-redux'
import { Field, reduxForm } from 'redux-form'
import { load as loadAccount } from './account'
const data = {
// used to populate "account" reducer when "Load" is clicked
firstName: 'Jane',
lastName: 'Doe',
age: '42',
anniversaryDate: '2018-08-22',
sex: 'female',
employed: true,
favoriteColor: 'Blue',
bio: 'Born to write amazing Redux code.'
}
const colors = ['Red', 'Orange', 'Yellow', 'Green', 'Blue', 'Indigo', 'Violet']
let InitializeFromStateForm = props => {
const { handleSubmit, load, pristine, reset, submitting } = props
return (
<form onSubmit={handleSubmit}>
<div>
<button type="button" onClick={() => load(data)}>
Load Account
</button>
</div>
<div>
<label>First Name</label>
<div>
<Field
name="firstName"
component="input"
type="text"
placeholder="First Name"
/>
</div>
</div>
<div>
<label>Last Name</label>
<div>
<Field
name="lastName"
component="input"
type="text"
placeholder="Last Name"
/>
</div>
</div>
<div>
<label>Age</label>
<div>
<Field name="age" component="input" type="number" placeholder="Age" />
</div>
</div>
<div>
<label>Anniversary Date</label>
<div>
<Field name="anniversaryDate" component="input" type="date" />
</div>
</div>
<div>
<label>Sex</label>
<div>
<label>
<Field name="sex" component="input" type="radio" value="male" />{' '}
Male
</label>
<label>
<Field name="sex" component="input" type="radio" value="female" />{' '}
Female
</label>
</div>
</div>
<div>
<label>Favorite Color</label>
<div>
<Field name="favoriteColor" component="select">
<option value="">Select a color...</option>
{colors.map(colorOption => (
<option value={colorOption} key={colorOption}>
{colorOption}
</option>
))}
</Field>
</div>
</div>
<div>
<label htmlFor="employed">Employed</label>
<div>
<Field
name="employed"
id="employed"
component="input"
type="checkbox"
/>
</div>
</div>
<div>
<label>Bio</label>
<div>
<Field name="bio" component="textarea" />
</div>
</div>
<div>
<button type="submit" disabled={pristine || submitting}>
Submit
</button>
<button type="button" disabled={pristine || submitting} onClick={reset}>
Undo Changes
</button>
</div>
</form>
)
}
// Decorate with reduxForm(). It will read the initialValues prop provided by connect()
InitializeFromStateForm = reduxForm({
form: 'initializeFromState' // a unique identifier for this form
})(InitializeFromStateForm)
// You have to connect() to any reducers that you wish to connect to yourself
InitializeFromStateForm = connect(
state => ({
initialValues: state.account.data // pull initial values from account reducer
}),
{ load: loadAccount } // bind account loading action creator
)(InitializeFromStateForm)
export default InitializeFromStateForm
React-Reduxのconnect()関数について少し説明します。
mapStateToProps で initialValues propが設定されています。initialValues は reduxForm が処理します。initialValues は { field1: 'value1', field2: 'value2' } の形をしており、componentWillMount() において form を初期化します。
initialValuesはここの例のようにpropで受け渡す以外に、reduxForm() のconfig parameterで受け渡す方法もあります。
mapDispatchToProps は object を指定することができます。この場合、objectの各fieldがaction creatorとなり、 React-Redux は dispatchをaction creatorにbindします。
connect() -React Redux
InitializeFromStateForm = connect(
state => ({ // mapStateToProps
initialValues: state.account.data
}),
{ load: loadAccount } // mapDispatchToProps
)(InitializeFromStateForm)
以下はindex.jsですが、オリジナルのものを最小化してあります。
import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import { createStore, combineReducers } from 'redux'
import { reducer as reduxFormReducer } from 'redux-form'
import account from './account'
const dest = document.getElementById('content')
const reducer = combineReducers({
account,
form: reduxFormReducer // mounted under "form"
})
const store = createStore(reducer)
const showResults = values =>
new Promise(resolve => {
setTimeout(() => {
// simulate server latency
window.alert(`You submitted:\n\n${JSON.stringify(values, null, 2)}`)
resolve()
}, 500)
})
let render = () => {
const InitializeFromStateForm = require('./InitializeFromStateForm').default
ReactDOM.hydrate(
<Provider store={store}>
<h2>Form</h2>
<InitializeFromStateForm onSubmit={showResults} />
</Provider>,
dest
)
}
render()
実行画面
初期画面です
「Load Account」ボタンでformを初期化します。最初の一回目だけ有効です。初期状態を変更してから、再度初期状態に戻すためには、UndoChangesボタンでreset()を発行する必要があります。
submitボタンを押します。
今回は以上です。