redux-form の FieldArray を使えば、
複数のデータを同時に編集して一括登録、
みたいなことができる。
表形式入力的なフォーム。
DataGrid もどき。
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { createStore, combineReducers } from 'redux';
import { Provider, connect } from 'react-redux';
import {
Field,
FieldArray,
reduxForm,
reducer as formReducer
} from 'redux-form';
import {
Grid,
Row,
Col,
Button,
Table,
FormGroup,
ControlLabel,
FormControl
} from 'react-bootstrap';
import '../node_modules/bootstrap/dist/css/bootstrap.css';
const ADD_CUSTOMERS = "ADD_CUSTOMERS";
function addCustomers(customers) {
return { type: ADD_CUSTOMERS, customers };
}
const initialState = {
customers: [
{ code: "10", name: "香川", kana: "カガワ" },
{ code: "4", name: "本田", kana: "ホンダ" },
{ code: "5", name: "長友", kana: "ナガトモ" },
{ code: "9", name: "岡崎", kana: "オカザキ" }
]
};
const customersReducer = (state = initialState, action) => {
switch (action.type) {
case ADD_CUSTOMERS:
return Object.assign({}, state, {
customers: [...state.customers, ...action.customers]
});
default:
return state;
}
};
const rootReducer = combineReducers({
customers: customersReducer,
form: formReducer
});
const store = createStore(rootReducer);
const validate = (values) => {
const errors = {};
if (!values.customers || values.customers.length == 0) {
errors.customers = { _error: "カスタマーを入力してください。" };
} else {
const customersArrayErrors = [];
values.customers.forEach((customer, index) => {
const customerErros = {};
if (customer && !customer.code) {
customerErros.code = "コードを入力してください。";
}
if (customer && !customer.name) {
customerErros.name = "名前を入力してください。";
}
if (customer && !customer.kana) {
customerErros.kana = "カナを入力してください。";
}
customersArrayErrors[index] = customerErros;
});
if (0 < customersArrayErrors.length) {
errors.customers = customersArrayErrors;
}
}
return errors;
};
const renderField = ({ input, type, meta: { touched, error } }) => (
<td>
<FormControl {...input} type={type}/>
{touched && error && <span className="text-danger">{error}</span>}
</td>
);
const renderCustomers = ({ fields, meta: { touched, error } }) => (
<Table>
<thead>
<tr>
<th>コード</th>
<th>名前</th>
<th>カナ</th>
</tr>
</thead>
<tbody>
{fields.map((customer, index) =>
<tr key={index}>
<Field
name={`${customer}.code`}
type="text"
component={renderField}/>
<Field
name={`${customer}.name`}
type="text"
component={renderField}/>
<Field
name={`${customer}.kana`}
type="text"
component={renderField}/>
</tr>
)}
{
touched && error &&
<tr>
<td><span className="text-danger">{error}</span></td>
<td></td>
<td></td>
</tr>
}
<tr>
<td>
<Button type="button" onClick={() => fields.push()}>
行追加
</Button>
</td>
<td></td>
<td></td>
</tr>
</tbody>
</Table>
);
class _CustomerTableForm extends Component {
render() {
const {
handleSubmit,
pristine,
reset,
submitting
} = this.props;
return (
<form onSubmit={handleSubmit}>
<FieldArray name="customers" component={renderCustomers} />
<FormGroup>
<Button bsStyle="primary"
type="submit"
disabled={submitting}>
保存
</Button>
<Button type="button"
disabled={pristine || submitting}
onClick={reset}>
リセット
</Button>
</FormGroup>
</form>
);
}
}
const CustomerTableForm = reduxForm({
form: "customerForm",
validate
})(_CustomerTableForm);
const CustomerTableFormContainer = connect(
state => {
return {};
},
dispatch => {
return {
onSubmit: (values) => {
dispatch(addCustomers(values.customers));
}
};
}
)(CustomerTableForm);
class CustomerList extends Component {
renderCustomers() {
return this.props.customers.map(c =>
<tr key={c.code}>
<td>{c.code}</td>
<td>{c.name}</td>
<td>{c.kana}</td>
</tr>
);
}
render() {
return (
<Table>
<thead>
<tr>
<th>コード</th>
<th>名前</th>
<th>カナ</th>
</tr>
</thead>
<tbody>
{this.renderCustomers()}
</tbody>
</Table>
);
}
}
const CustomerListContainer = connect(
state => {
return { customers: state.customers.customers };
}
)(CustomerList);
class App extends Component {
render() {
return (
<Grid>
<Row>
<Col md={12}>
<CustomerTableFormContainer />
<CustomerListContainer />
</Col>
</Row>
</Grid>
);
}
}
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("app")
);
だんだん、バリデーションのための関数を書くのがメンドクなってきた。