【发布时间】:2015-10-05 22:01:26
【问题描述】:
我有一个非常大的动态表单,它根据通过 AJAX 收集的数据呈现。
有一个包含表格的表格。该表包含一个标题,然后是一系列行(由状态数据确定)。然后每一行都有一系列单元格(也由状态数据决定)。每个单元格都包含一个复选框。
我的问题是关于在哪里维护大量复选框的状态。最初我的方法是让复选框控制组件,每个单元格都保持其复选框的状态。
我还尝试将选择框的状态实现为父表单组件本身的状态。
前一种方法的问题在于,当我提交表单时,我没有表单级别的状态,因为它隐藏在单元格后代中。我能以某种方式获得这种状态吗? findDomNode 似乎只是当前组件,而不是级联。此外,报头单元格在选中列中的所有行时,都会检查复选框,此解决方案不会使我能够更新该信息。
后一种方法的问题是,当我对一个复选框进行更改时,状态更改会导致表单组件重新渲染,进而导致整个表格重新渲染(或至少调用它的渲染方法)。这非常耗时,而且对于一个大表(通常可以是 100x50)需要非常不友好的时间来重新渲染。
归根结底,选中复选框的影响应该很小。复选框本身应该更新,如果列的全选状态发生变化,可能需要更新列标题以选中/取消选中。就是这样。
我已经删除了很多代码,但这基本上是我正在使用的。知道表格中的单元格复选框会跟踪应将哪些标签应用于图像可能会有所帮助。表头单元跟踪哪些标记(从图像名称中提取的文本)映射到哪些标记。当这种情况发生变化时,必须重新呈现该列(另一个我尚未解决的问题,我怀疑如果不完全重新呈现所有内容,这将再次变得困难)。
var AutoTagForm = React.createClass({
getInitialState: function() {
return {data: {
tags: [],
images: {},
tokens: [],
tokenTagMap: {}
}
};
},
componentDidMount: function() {
$.ajax({
url: this.props.url,
type: "POST",
data: { imageIds: this.props.images },
dataType: 'json',
cache: false,
success: function(data) {
this.setState({data: data});
}.bind(this),
error: function(xhr, status, err) {
console.error(this.props.url, status, err.toString());
}.bind(this)
});
},
onSubmit: function(e) {
e.preventDefault()
// Submit the updates to the server
},
cellCheckedChange: function(image, tag) {
// If the image has the tag, add it. Otherwise remove it
var tagIndex = image.checkedTags.indexOf(tag)
// TODO Perhaps it is safer to find the image object in this.state.data?
if (tagIndex === -1) {
image.checkedTags.push(tag);
} else {
image.checkedTags.splice(tagIndex, 1);
}
this.setState({
data: this.state.data
})
},
render: function() {
var images = this.state.data.images;
var tokenTagMap = this.state.data.tokenTagMap;
var cellCheckedChange = this.cellCheckedChange;
var rowNodes = Object.keys(images).map(function(key){
if (images.hasOwnProperty(key)) {
var image = images[key];
return (
<AutoTagImageRow key={image.id}
image={image}
tokenTagMap={tokenTagMap}
cellCheckedChange={cellCheckedChange} />
);
}
});
return (
<form ref="form" onSubmit={this.onSubmit} id="updateAllForm" className={'autotagForm'}>
<div>
<input type="submit"
value="Apply" />
</div>
<div>
<table>
<thead>
<AutoTagHeaderRow tags={this.state.data.tags}
tokens={this.state.data.tokens}
tokenTagMap={this.state.data.tokenTagMap} />
</thead>
<tbody>
{rowNodes}
</tbody>
</table>
</div>
</form>
);
}
});
var AutoTagImageRow = React.createClass({
render: function() {
var image = this.props.image;
var tokenTagMap = this.props.tokenTagMap;
var cellCheckedChange = this.props.cellCheckedChange;
var cellNodes = Object.keys(tokenTagMap).map(function(token){
if (tokenTagMap.hasOwnProperty(token)) {
return (
<AutoTagImageRowCell image={image}
token={token}
tokenTagMap={tokenTagMap}
cellCheckedChange={cellCheckedChange} />
);
}
});
return (
<tr>
{cellNodes}
<td>{image.clientPath}</td>
</tr>
);
}
});
var AutoTagImageRowCell = React.createClass({
isTagged: function() {
var image = this.props.image;
var token = this.props.token;
var tokenTagMap = this.props.tokenTagMap;
var tag = tokenTagMap[token];
return (image.tags.indexOf(tag) !== -1);
},
isChecked: function() {
var image = this.props.image;
var token = this.props.token;
var tokenTagMap = this.props.tokenTagMap;
var tag = tokenTagMap[token];
return (image.checkedTags.indexOf(tag) !== -1);
},
handleCheckedChange: function() {
var image = this.props.image;
var token = this.props.token;
var tokenTagMap = this.props.tokenTagMap;
var tag = tokenTagMap[token];
this.props.cellCheckedChange(image, tag);
},
render: function() {
var className = '';
if (this.isTagged()) {
className = 'success';
}
return (
<td className={className}>
<input type="checkbox"
checked={this.isChecked()}
onChange={this.handleCheckedChange} />
</td>
);
}
});
我是 React 新手,可能会做出一些糟糕的设计决定!这与我之前使用简单的 javascript 做事的方式非常不同,我热衷于遵循 React 哲学,但我觉得它几乎立刻就出错了,因为这是我尝试做的第一件事通过教程。
【问题讨论】:
标签: javascript reactjs