Examples组件从Definition组件接收数据(示例列表)。由于这些示例可以由用户编辑,因此它们以状态形式放置,状态表单还允许我们在每次状态更改时创建/删除其他字段。
输入(handleChangeExample函数)上的每次击键都会改变状态,但似乎属性(props.examples)也会更新,我无法理解为什么会这样做。
我相信在整个周期中,Examples组件属性应该保持不变/不变,除非我们显式保存块(saveBlock函数),它依次触发来自parent-Definition组件的saveExamples函数。
var Examples = React.createClass({
getInitialState: function() {
return {
examples: this.props.examples
}
},
editBlock: function(event) {
// this.setState({examples: this.props.examples});
this.setState({editingBlock: !this.state.editingBlock});
},
saveBlock: function(event) {
var that = this;
var filtered_examples = [];
this.state.examples.forEach(function(example) {
if (example !== '') {
filtered_examples.push(example);
}
});
this.props.saveExamples(filtered_examples);
},
handleChangeExample: function(i) {
var updated_examples = this.state.examples;
updated_examples[i] = this.refs['example_' + i].getDOMNode().value.trim();
this.setState({examples: updated_examples});
},
render: function() {
var that = this;
var fields = {};
console.log(this.props.examples);
console.log(this.state.examples);
this.state.examples.forEach(function(example, i) {
if (example !== '') {
fields['example-' + i] =
<li className='editing__entry'>
<input type='text'
key={i}
ref={'example_' + i}
onChange={that.handleChangeExample.bind(null, i)}
defaultValue={example} />
</li>;
}
});
fields['example-' + (this.state.examples.length+1)] =
<li className='editing__entry'>
<input type='text'
key={this.state.examples.length+1}
ref={'example_' + (this.state.examples.length+1)}
onChange={that.handleChangeExample.bind(null, (this.state.examples.length+1))}
defaultValue='' />
</li>;
return (
<section className='definition__examples block'>
<div className='editing'>
<ul className='editing__fields'>
{fields}
</ul>
</div>
<button onClick={this.saveBlock} className='button--primary--small'>Save changes</button>
</section>
);
}
});
var Definition = React.createClass({
getInitialState: function() {
return {
examples: this.props.definition.examples
}
},
saveExamples: function(examples) {
this.setState({examples: examples});
},
render: function() {
var editingMode = this.props.editingMode;
var object = this;
return (
<li className='definition'>
<Examples editingMode={editingMode}
examples={this.state.examples}
saveExamples={this.saveExamples} />
</li>
);
}
});
module.exports = Definition;
答案 0 :(得分:1)
您看到此行为是因为this.state.examples
只是对this.props.examples
的引用。
this.props.examples
正在更新,原因与普通JavaScript中的预期行为相同:
> var a = [ 'abc', 'def', 'ghi' ];
undefined
> a
[ 'abc', 'def', 'ghi' ]
> var b = a;
undefined
> b
[ 'abc', 'def', 'ghi' ]
> b[1] = 'DEF';
'DEF'
> b
[ 'abc', 'DEF', 'ghi' ]
> a
[ 'abc', 'DEF', 'ghi' ]
有几种方法可以解决这个问题。一种是创建this.props.examples
的副本并将其设置为this.state.examples
(您可以通过Array.prototype.slice执行此操作):
getInitialState: function() {
return {
examples: this.props.examples.slice()
}
}
我认为这将适用于您的情况,因为examples
只是一个字符串数组。但是,slice
只会创建数组的浅表副本,因此如果元素是对象或数组,您仍然会更新this.props.examples
。
另一种选择是使用Immutability Helpers来更新您的州。您可能还想查看immutable-js。
以下是一个简单的示例,说明如何使用Immutability Helpers执行您要执行的操作:jsfiddle。
/** @jsx React.DOM */
var SomeComponent = React.createClass( {
getInitialState : function() {
return {
examples : this.props.examples,
}
},
_handleChange : function( index, e) {
var updateObj = {};
updateObj[ index ] = { $set : e.target.value };
var newData = React.addons.update( this.state.examples, updateObj );
this.setState( { examples : newData } );
},
render : function() {
return (
<div>
<input onChange={this._handleChange.bind(this, 0)}/><br/>
<input onChange={this._handleChange.bind(this, 1)}/><br/>
props:
<pre>{JSON.stringify(this.props.examples,null,2)}</pre>
state:
<pre>{JSON.stringify(this.state.examples,null,2)}</pre>
</div>
);
}
} );
React.renderComponent(<SomeComponent examples={ [ "ABC", "DEF" ] } />, document.getElementById( 'main' ) );