Ben*_*ley 4 javascript html-table reactjs
我试图在React中创建一个表组件,其中列和行都是动态的并随时间而变化.但是,当数据发生更改时,React会抛出意外的DOM突变不变违规.
这是一个演示http://jsfiddle.net/69z2wepo/1797/问题的小提琴.如您所见,数据在初始渲染后发生变化,React无法再跟踪DOM的状态.
代码在这里:
var Table = React.createClass({
getDefaultProps: function() {
return {
data: [
{
colA: { value: 'foo' },
},
],
};
},
render: function() {
return (
<table>
<thead>
<tr> {
Object.keys(this.props.data[0]).map(function(key) {
return (<th>{ key }</th>);
}.bind(this))
} </tr>
</thead>
<tbody> {
this.props.data.map(function(item) {
return (<tr> { Object.keys(item).map(function(key) {
return (
<td>{ item[key] }</td>
);
}.bind(this)) } </tr>);
}.bind(this))
} </tbody>
</table>
);
}
});
var Main = React.createClass({
componentWillMount: function() {
setTimeout(function() {
var data = [
{
colA: {
value: 'foobar',
},
},
];
this.setState({
data: data,
});
}.bind(this), 3000);
},
getInitialState: function() {
var data = [
{
colA: {
value: 'foo',
},
colB: {
value: 'bar',
}
},
{
colA: {
value: 'foo',
},
colB: {
value: 'bar',
}
}
];
return {
data: data,
};
},
render: function() {
return (<Table data={ this.state.data } />);
},
});
React.render(<Main />, document.body);
console.log(React.renderToString(<Table/>));
Run Code Online (Sandbox Code Playgroud)
我已经尝试过各种方式添加关键属性来跟踪各种元素,似乎没有什么能解决这个问题.
使用renderToString呈现表组件显示React正在表的各个级别插入一堆元素.这是可能的原因吗?查看此处呈现的DOM:
<table data-reactid=".1" data-react-checksum="1098817301">
<thead data-reactid=".1.0">
<tr data-reactid=".1.0.0">
<span data-reactid=".1.0.0.0"> </span>
<th data-reactid=".1.0.0.1:0">colA</th>
<span data-reactid=".1.0.0.2"> </span>
</tr>
</thead>
<tbody data-reactid=".1.1">
<span data-reactid=".1.1.0"> </span>
<tr data-reactid=".1.1.1:0">
<span data-reactid=".1.1.1:0.0"> </span>
<td data-reactid=".1.1.1:0.1:0"><span data-reactid=".1.1.1:0.1:0.$value:0">foo</span></td>
<span data-reactid=".1.1.1:0.2"> </span>
</tr>
<span data-reactid=".1.1.2"> </span>
</tbody>
</table>
Run Code Online (Sandbox Code Playgroud)
结果问题是你的缩进.如果你{}在一个新行开始花括号(花括号在JSX中编写javascript),你的代码就可以了.不知道为什么会发生这种情况.
jsfiddle:http://jsfiddle.net/cwn2nebs/
var Table = React.createClass({
getDefaultProps: function() {
return {
data: [
{
colA: { value: 'foo' },
},
],
};
},
render: function() {
return (
<table>
<thead>
<tr>
{
Object.keys(this.props.data[0]).map(function(key, idx) {
return (<th key={ idx } >{ key }</th>);
}.bind(this))
}
</tr>
</thead>
<tbody>
{
this.props.data.map(function(item, idx) {
return (
<tr key={ idx }>
{
Object.keys(item).map(function(key, i) {
return (
<td key={ i }>{ item[key] }</td>
);
}.bind(this)) }
</tr>);
}.bind(this))
}
</tbody>
</table>
);
}
});
var Main = React.createClass({
componentWillMount: function() {
setTimeout(function() {
var data = [
{
colA: {
value: 'foobar',
}
},
];
this.setState({
data: data,
});
}.bind(this), 3000);
},
getInitialState: function() {
var data = [
{
colA: {
value: 'foo',
},
colB: {
value: 'bar',
}
},
{
colA: {
value: 'foo',
},
colB: {
value: 'bar',
}
}
];
return {
data: data,
};
},
render: function() {
return (<Table data={ this.state.data } />);
},
});
React.render(<Main />, document.body);
Run Code Online (Sandbox Code Playgroud)
更新
使用JSX编译器我试图将部分代码转换为纯JS:
render: function() {
return (
React.createElement("table", null,
React.createElement("thead", null,
React.createElement("tr", null, " ",
Object.keys(this.props.data[0]).map(function(key, idx) {
return (React.createElement("th", {key: idx }, key ));
}.bind(this)),
" ")
),
React.createElement("tbody", null, " ",
this.props.data.map(function(item, idx) {
return (React.createElement("tr", {key: idx }, " ", Object.keys(item).map(function(key, i) {
return (
React.createElement("td", {key: i }, item[key] )
);
}.bind(this)), " "));
}.bind(this)),
" ")
)
);
}
Run Code Online (Sandbox Code Playgroud)
这是如何React.createElement工作:
React.createElement(type, props, children);
Run Code Online (Sandbox Code Playgroud)
注意tr元素的空子元素:
React.createElement("tr", null, " ",
Object.keys(this.props.data[0]).map(function(key, idx) {
return (React.createElement("th", {key: idx }, key ));
}.bind(this)),
" ")
Run Code Online (Sandbox Code Playgroud)
但是在新行上使用花括号,编译后的代码看起来像这样(没有空("")子代):
React.createElement("tr", null,
Object.keys(this.props.data[0]).map(function(key, idx) {
return (React.createElement("th", {key: idx }, key ));
}.bind(this))
)
Run Code Online (Sandbox Code Playgroud)
我相信当你发现时,React会将" "孩子转换成span导致问题的元素.