web-dev-qa-db-ja.com

React.jsでリッチデータ構造を編集する

データ構造用の単純なグリッドベースのエディターを作成しようとしていますが、React.jsにいくつかの概念的な問題があります。彼らのドキュメントはこれに関してあまり役に立たないので、ここの誰かが助けてくれることを望んでいます。

まず、外部コンポーネントから内部コンポーネントに状態を転送する正しい方法は何ですか?内部コンポーネントの状態を「バブルアップ」して外部コンポーネントに変更することはできますか?

第二に、2つの別々のコンポーネントがデータを共有できるため、一方の変異が他方の変異に見えるようになりますか?

以下は、私がやりたいことの簡単な例です( JSFiddle version ):

companyオブジェクトの配列を含むemployeeオブジェクトがあります。編集可能なグリッドにemployeeリストをレイアウトしたい。ボタンをクリックすると、結果のcompanyオブジェクトと、突然変異(コンソールへの書き込み)が表示されます。

/** @jsx React.DOM */

var Cell = React.createClass({
    getInitialState: function () {
        return {data: ""};
    },

    componentWillMount: function () {
        this.setState({data: this.props.data});
    },
    onChange: function (evt) {
        console.log(this.state, evt.target.value);
        this.setState({data: evt.target.value});
    },
    render: function () {
        var data = this.props.data;
        return <input value={this.state.data} onChange={this.onChange} />
    }
});

var Row = React.createClass({
    render: function () {
        return (<div className="row">
            <Cell data={this.props.data.name} />
            <Cell data={this.props.data.location} />
            <Cell data={this.props.data.phone} />
        </div>);
    }
});

var Grid = React.createClass({
    render: function () {
        var rows = this.props.data.map(function (rowData, index) {
            return <Row key={index} data={rowData}>Row</Row>;
        });
        return <div className="table">{rows}</div>;
    }
});

var Button = React.createClass({
    getInitialState: function () {
        return {data: {}}
    },
    componentWillMount: function () {
        this.setState({data: this.props.data});
    },
    onClick: function () {
        console.log(this.state);
    },
    render: function () {
        return <button onClick={this.onClick}>Update</button>;
    }
});

var company = {
    name: "Innotech",
    employees: [
        {id: "1", name: "Peter", location: "IT", phone: "555-1212"},
        {id: "2", name: "Samir", location: "IT", phone: "555-1213"},
        {id: "3", name: "Milton", location: "loading dock", phone: "none"}
    ]
};


React.renderComponent(
    <div><Grid data={company.employees} /><Button data={company} /></div>,       
    document.getElementById('employees')
);
46
Andrew

これはReactの最も文書化されていない部分だと思います。コンポーネント間で通信するための推奨される方法は、親から子に通信するときに単純にプロップを設定し、親に。

兄弟コンポーネント間でデータを共有したいと思う場合、状態を管理して両方のコンポーネントに渡す親コンポーネントが存在する必要があることを意味します。ほとんどの場合、状態はコンポーネント階層の最上部近くに存在し、各情報は(せいぜい)1つのコンポーネントの状態に存在する必要があります。

これについてもう少し詳しくは、Pete Huntのブログ投稿Reactで考えるを参照してください。


これを念頭に置いて、 fiddle を更新しました。

Gridを変更して、独自の状態を維持せず、代わりに小道具を介して渡されたデータを常に表示し、必要なときに小道具からonCellChangeを呼び出しますrequest親からのデータの変更。 (Gridコンポーネントは、その親が修正されたデータでグリッドのdataプロパティを更新することを期待します。親が拒否した場合(データ検証の失敗などにより)、読み取り専用になりますグリッド。)

また、グリッドとその兄弟ボタンをラップする新しいEditorコンポーネントを作成したことにも気付くでしょう。 Editorコンポーネントは、本質的にページ全体を管理するようになりました。実際のアプリでは、グリッドのコンテンツが他の場所で必要になる可能性が高いため、状態が高くなります。 Buttonコンポーネントを削除したのは、ネイティブの<button>タグをはるかに超えていなかったためです。 Cellを残しましたが、削除することもできます-Row<input>タグを直接簡単に使用できます。

これが理にかなっていることを願っています。不明な点がある場合はお気軽にお問い合わせください。通常、 #reactjs IRC room の周りに人がいます。これについて詳しく知りたい場合は、.

53
Sophie Alpert

過去1週間ほどReactJSを調査してきました。あなたの質問への私の入力は、新しい質問をすることです:なぜCellコンポーネントをRowおよびGridコンポーネントから分離するのですか?

バックボーンのバックグラウンドから来たCell&Row&Gridは、個々のCell Backbone.Viewをきめ細かく制御するのに理にかなっています。ただし、ReactJSが解決しようとしているのは、詳細な制御とDOMの更新であるように思われます。

var Grid = React.createClass({
    onChange: function(evt, field) {
        this.props.data[field] = evt.target.value;
    },

    render: function () {
        var rows = this.state.data.map(function (rowData, index) {
            return (
                <div className="row" key={index}>
                    <input value={rowData.name} onChange={this.onChange.bind(null, "name")} />
                    <input value={rowData.location} onChange={this.onChange.bind(null, "location")} />
                    <input value={rowData.phone} onChange={this.onChange.bind(null, "phone")} />
                </div>
            );
        });

        return <div className="table">
                   {rows}
               </div>;
    }
});

(on * Changeの処理は無視してください。改善の余地があります。テストされていないコード)

問題は、セルまたは行を他の場所で個々のコンポーネントとして再利用することはありますか?私にとって、答えは「非常にありそうもない」です。その場合、上記の私のソリューションは理にかなっています、私見、そしてデータを渡す問題と上下の問題を取り除きます。

7
Bernardo

親コンポーネントが意味をなさないときに兄弟コンポーネント間でデータを共有する別の方法は、コンポーネント間でイベントを使用することです。たとえば、Backbone.Events、ブラウザに移植されたNode.js Emitter、または同様のライブラリを使用できます。リアクティブストリームを好む場合は、Bacon.jsを使用することもできます。 Bacon.jsとReact.jsを組み合わせた素晴らしいシンプルな例がここにあります: http://joshbassett.info/2014/reactive-uis-with-react-and-bacon/

0
DjebbZ