React ref Order 有保证吗?

IT技术 javascript reactjs
2021-05-02 19:57:45

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

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'));
.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;
}
<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来自填充它this.props.items.map- 但为了论证,假设在我发现自己所处的实际情况下这是不可能的。

1个回答

文件说:

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