我使用React构建一个具有未知数量子节点的元素,我需要对每个元素进行引用。请考虑以下代码:
cooking

class Items extends React.Component {
constructor() {
super();
this.itemEls = [];
}
render() {
return (
<div>
{
this.props.items.map((item, index) => {
return <div className="item" key={index} ref={(el) => this.itemEls.push(el)}>{item}</div>;
})
}
</div>
);
}
componentDidMount() {
console.log(this.itemEls.map((el) => el.innerHTML));
}
}
ReactDOM.render(<Items items={["Hello", "World", "Foo", "Bar"]} />, document.getElementById('container'));
&#13;
.item {
display: inline-block;
background: #EEE;
border: 1px solid #DDD;
color: #999;
padding: 10px;
font-family: sans-serif;
font-weight: bold;
margin: 10px;
border-radius: 5px;
cursor: default;
}
&#13;
我循环遍历提供的数组,并在我去的时候保存对每个元素的引用。当组件安装时,我按照它们添加到阵列的顺序打印出元素内容的列表。到目前为止,在我的所有测试中,订单都是正确的,但是我找不到任何文件证实这不仅仅是在后台发生秘密竞争条件的最常见结果。
参考函数的调用顺序是否一致?
这里显而易见的解决方案是在<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="container"></div>
中预先设置数组长度并使用componentWillMount
中的index
值填充它 - 但为了争论,请让&#39 ; s说在我发现自己的实际情况中是不可能的。
答案 0 :(得分:4)
ref属性采用回调函数,回调函数为 在安装或卸载组件后立即执行。
使用map
安装的组件显然按正确的顺序安装,因此我猜测ref回调是按顺序执行的。如果你怀疑ref回调可能是异步的,我认为你可以通过从回调中抛出一个错误来验证这个假设 - 如果执行在第一个元素处停止,那么它是同步的(如果我错了,请有人纠正我)。
如果您仍然担心,可以通过项目索引而不是推送将元素添加到数组中(这可能就是我要做的事情):
this.props.items.map((item, index) => {
return <div className="item" key={index} ref={(el) => {this.itemEls[index] = el} }>{item}</div>;
})
通过这种方式,您将受到map
跳过的空项目的保护,例如:
let a = [];
let b = [];
let items = ['Hello', 'World', 'Foo', , ,'Bar']; // items.length == 6
delete items[1];
items.map( i => { a.push( i ); return i });
console.log( a ); // [ "Hello", "Foo", "Bar" ]
// - the index of "Foo" and "Bar" doesn't match original index
items.map( (i, idx) => { b[idx] = i; return i });
console.log( b ); // [ "Hello", <empty>, "Foo", <empty>, <empty>, "Bar" ]
// sparse array, but matching indexes