在 React.js 中编辑丰富的数据结构 [英] Editing a rich data structure in React.js
问题描述
我正在尝试为数据结构创建一个简单的基于网格的编辑器,但我在使用 React.js 时遇到了一些概念上的问题.他们的文档对此不是很有帮助,所以我希望这里有人可以提供帮助.
首先,将状态从外部组件转移到内部组件的正确方法是什么?内部组件的状态变化是否可能冒泡"到外部组件?
第二,两个独立的组件是否可以共享数据,以便一个的突变在另一个中可见?
以下是我想做的事情的简化示例(JSFiddle 版本):
我有一个 company
对象,其中包含一组 employee
对象.我想在可编辑的网格中布置 employee
列表.当我单击按钮时,我想查看生成的 company
对象,以及任何更改(写入控制台).
/** @jsx React.DOM */var Cell = React.createClass({getInitialState: 函数 () {返回{数据:"};},componentWillMount: 函数 () {this.setState({data: this.props.data});},onChange: 函数 (evt) {console.log(this.state, evt.target.value);this.setState({data: evt.target.value});},渲染:函数(){var data = this.props.data;return <input value={this.state.data} onChange={this.onChange}/>}});var Row = React.createClass({渲染:函数(){return (<div className="row"><单元格数据={this.props.data.name}/><单元格数据={this.props.data.location}/><单元数据={this.props.data.phone}/>
);}});var Grid = React.createClass({渲染:函数(){var rows = this.props.data.map(function (rowData, index) {return <Row key={index} data={rowData}>Row</Row>;});return
;}});var Button = React.createClass({getInitialState: 函数 () {返回{数据:{}}},componentWillMount: 函数 () {this.setState({data: this.props.data});},onClick: 函数 () {控制台日志(这个状态);},渲染:函数(){return <button onClick={this.onClick}>Update</button>;}});var 公司 = {name: "Innotech",雇员: [{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><网格数据={company.employees}/><按钮数据={company}/></div>,document.getElementById('员工'));
我认为这是目前 React 中文档最少的部分.建议的组件间通信方式是在父级与子级通信时简单地设置 props,在子级与父级通信时通过 props 传递回调.
当您觉得要在兄弟组件之间共享数据时,这意味着应该有一个父组件管理状态并将其传递给两个组件.大多数情况下,您的状态应该位于组件层次结构的顶部附近,并且每条信息都应该(最多)位于一个组件的状态中,而不是更多.
有关这方面的更多信息,请参阅 Pete Hunt 的博客文章,React 中的思考.
<小时>考虑到这一点,我更新了您的fiddle.
我已经更改了 Grid
以便它不维护自己的状态而是始终显示通过其 props 传递的数据,并在以下情况下从其 props 调用 onCellChange
它想请求从其父级更改数据.(Grid
组件将期望其父组件使用修改后的数据更新网格的 data
属性.如果父组件拒绝(可能是因为数据验证失败或类似原因),您将结束使用只读网格.)
您还会注意到我创建了一个新的 Editor
组件来包装网格及其同级按钮.Editor
组件现在基本上管理整个页面.在真正的应用程序中,很可能其他地方需要网格的内容,因此状态会移到更高的位置.我删除了你的 Button
组件,因为它除了原生的 标签之外没有做太多事情;我离开了
Cell
但它也可以被删除 -- Row
可以很容易地直接使用 <input>
标签.
希望这是有道理的.如果有什么不清楚的,请随时询问.#reactjs IRC 聊天室中通常也有人,如果你想多聊聊的话关于任何这些.
I'm trying to create a simple grid-based editor for a data structure and I'm having a couple conceptual problems with React.js. Their documentation is not very helpful on this, so I'm hoping someone here can help.
First, what is the correct way to transfer state from an outer component to an inner component? Is it possible to have state changes in the inner component "bubble up" to the outer component(s)?
Second, can two separate components share data, so that a mutation in one is visible in the other?
Below is a simplified example of the sort of thing I want to do (JSFiddle version):
I have a company
object containing an array of employee
objects. I want to lay out the employee
list in an editable grid. When I click the button, I want to see the resulting company
object, along with any mutations (writes to the console).
/** @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')
);
I think this is the most underdocumented part of React right now. The suggested way to communicate between components is to simply set props when communicating from parent to child and to pass callbacks through props when communicating from child to parent.
When you feel that you want to share data between sibling components, it means that there should be a parent component managing the state and passing it to both components. Most of the time, your state should live near the top of your component hierarchy, and each piece of info should live in (at most) one component's state, not more.
For a bit more about this, see Pete Hunt's blog post, Thinking in React.
With this in mind, I've updated your fiddle.
I've changed Grid
so that it doesn't maintain its own state but instead always displays the data passed via its props, and calls onCellChange
from its props when it wants to request a change of the data from its parent. (The Grid
component will expect its parent to update the grid's data
prop with the modified data. If the parent refuses (perhaps because of failed data validation or similar), you end up with a read-only grid.)
You'll also notice that I created a new Editor
component to wrap the grid and its sibling button. The Editor
component now essentially manages the entire page. In a real app, it's likely that the contents of the grid would be needed elsewhere and so the state would be moved higher. I removed your Button
component because it wasn't doing much beyond the native <button>
tag; I left Cell
but it too could be removed -- Row
could easily use <input>
tags directly.
Hope this makes sense. Feel free to ask if anything's unclear. There are usually also people around in the #reactjs IRC room if you want to chat more about any of this.
这篇关于在 React.js 中编辑丰富的数据结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!