かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

TypeScript + Reactでredux-formを使ったDeep formのサンプル

以下の例にあるようなDeep formを作ってみようと思いました。

erikras.github.io

結果

型定義にはそんなものなかった。

解決策

any最高!

import * as React from 'react';
import * as Redux from 'redux';
import * as ReduxForm from 'redux-form';
import * as reducers from '../reducers';
import Order from '../models/Order';
import OrderDetail from '../models/OrderDetail';
import * as orderActions from '../actions/orderActions';

interface IndexPageProps extends ReduxForm.ReduxFormProps {
    order?: (order: Order) => void;
    shippedOrder?: Order;
}

interface OrderFormData {
    name: string;
    orders: OrderDetailFormData[];
}

interface OrderDetailFormData {
    name: string;
    price: string;
}

class IndexPage extends React.Component<IndexPageProps, {}> {
    constructor(props: IndexPageProps) {
        super(props);
        this.onSubmit = this.onSubmit.bind(this);
    }

    private onSubmit(data: OrderFormData) {
        let details = data.orders.map(x => {
            return {
                name: x.name,
                price: parseFloat(x.price)
            } as OrderDetail;
        });
        let order = {
            name: data.name,
            details: details
        } as Order;

        this.props.order(order);
    }

    render() {
        const {
            handleSubmit,
            fields: {name, orders}
        } = this.props;
        // anyにして、どうにでもなーれ
        let orderDetails = orders as any;
        let orderDetailForms = orderDetails.map(x => (
            <div>
                <hr />
                <h3>Order detail</h3>
                <div>
                    <label>name</label>
                    <input type='text' {...x.name} />
                </div>
                <div>
                    <label>price</label>
                    <input type='text' {...x.price} />
                </div>
            </div>
        ));
        return (
            <div>
                <form onSubmit={handleSubmit(this.onSubmit)}>
                    <div>
                        <input type='submit' />
                    </div>
                    <div>
                        <label>Name</label>
                        <input type='text' {...name}/>
                    </div>
                    <div>
                        <button onClick={e => {
                            e.preventDefault();
                            orderDetails.addField(); // ここで子フォームを追加
                        }}>Add Order detail</button>
                    </div>
                    <div>
                        {orderDetailForms}
                    </div>
                </form>
                {this.props.shippedOrder.name && (
                    <div>
                        <hr />
                        <span>Order shipped: </span>
                        <span>{this.props.shippedOrder.name}</span>
                    </div>
                )}
            </div>
        );
    }
}

function select(state: reducers.AppState): IndexPageProps {
    return {
        shippedOrder: state.order
    };
};

export default ReduxForm.reduxForm({
    form: 'IndexPage',
    fields: ['name', 'orders[].name', 'orders[].price']
}, select, {
    order: orderActions.order
})(IndexPage);

実行するとこんな感じ。

f:id:okazuki:20160124165346p:plain

型定義に頑張ってほしい。

ソース

ソースは以下にアップしました。

github.com