在React.js中编辑丰富的数据结构

And*_*rew 46 javascript reactjs

我正在尝试为数据结构创建一个简单的基于网格的编辑器,我对React.js有一些概念上的问题.他们的文档对此没有多大帮助,所以我希望有人可以提供帮助.

首先,将状态从外部组件转移到内部组件的正确方法是什么?是否有可能将内部组件中的状态更改"冒泡"到外部组件?

其次,两个独立的组件可以共享数据,从而一个中的突变在另一个中可见吗?

下面是我想要做的事情的简化示例(JSFiddle版本):

我有一个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')
);
Run Code Online (Sandbox Code Playgroud)

Sop*_*ert 53

我认为这是React目前最缺乏文档的部分.在组件之间进行通信的建议方法是在从父级到子级进行通信时简单地设置道具,并在从子级到父级进行通信时通过props传递回调.

当您认为要在兄弟组件之间共享数据时,这意味着应该有一个父组件来管理状态并将其传递给两个组件.大多数情况下,您的状态应该位于组件层次结构的顶部附近,并且每条信息应该(最多)存在于一个组件的状态中,而不是更多.

有关这方面的更多信息,请参阅Pete Hunt的博文" Thinking in React".


考虑到这一点,我已经更新了你的小提琴:

http://jsfiddle.net/spicyj/M6h22/

我已经改变,Grid以便它不保持自己的状态,而是始终显示通过其props传递的数据,并onCellChange在它想要请求从其父级更改数据时从其props 调用.(该Grid组件将期望其父级data使用修改后的数据更新网格的prop.如果父级拒绝(可能是因为数据验证失败或类似),您最终会得到一个只读网格.)

您还会注意到我创建了一个新Editor组件来包装网格及其兄弟按钮.该Editor组件现在基本上管理整个页面.在一个真实的应用程序中,很可能在其他地方需要网格的内容,因此状态会更高.我删除了你的Button组件,因为它没有超出本机<button>标签; 我离开了Cell但也可以删除 - Row可以<input>直接使用标签.

希望这是有道理的.随意询问是否有任何不清楚的地方.如果您想要更多地了解这些内容,那么#reactjs IRC会议室周围通常也有人.


Ber*_*rdo 7

过去一周左右我一直在探索ReactJS.我对您的问题的输入是一个新问题:为什么要将Cell组件与Row和Grid组件分开?

来自Backbone背景,Cell&Row&Grid是有意义的,可以对单个Cell Backbone.Views进行精细控制.但是,似乎粒度控制和DOM更新是ReactJS试图为您解决的问题,对我来说,有一个Grid组件在其内部实现了一个Row/Cell:

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>;
    }
});
Run Code Online (Sandbox Code Playgroud)

(忽略on*更改处理,有改进的余地.未经测试的代码)

问题是,您是否会在其他地方重复使用Cell或Row作为单独的组件?对我来说,答案是"非常可能没有".在这种情况下,我的解决方案是有道理的,恕我直言,并摆脱了传递数据和上下变化的问题.