React:如何将裁判转发给多个孩子?

时间:2018-12-11 06:17:20

标签: reactjs

我正在尝试将多个引用转发到多个子DOM节点:
我需要引用这7个按钮,因此可以在它们之间进行集中管理。
我尝试使用React.createRef()数组,然后使用 index 将此数组的每个元素附加到子级,但是所有引用都指向最后一个按钮。
为什么并且还有其他解决方案?

class RestaurantsList extends Component {
  references = Array(7).fill(React.createRef());

  render() {
    return (
      <ul 
        id="restaurants-list"
        role="menu"
      >
        {
          this.props.restaurants.map((restaurant, index) => {
            return (
              <Restaurant 
                ref={this.references[index]}
                name={restaurant.name}
              />
            );
          })
        }
      </ul>
    );
  }
}

const Restaurant = React.forwardRef((props, ref) => {
  return (
    <li>
      <button 
        ref={ref}
      >
        {name}
      </button>
    </li>
  );
})

1 个答案:

答案 0 :(得分:2)

正如注释中所讨论的,最好的方法是将引用列表保留为父组件内的数组或对象属性。

对于Array.prototype.fill(),其参数仅计算一次。因此,您需要使用.map()来获取唯一的引用对象。

references = Array(7).fill(0).map(() => React.createRef());

无论如何,在现实世界中,这宁愿发生在constructor()componentDidUpdate()中。

但是我认为最好使用哈希图:

references = {};

getOrCreateRef(id) {
    if (!this.references.hasOwnProperty(id)) {
        this.references[id] = React.createRef();
    }
    return this.references[id];
}

render() {
    return (
    ....
    {
      this.props.restaurants.map((restaurant, index) => {
        return (
          <Restaurant 
            ref={this.getOrCreateRef(restaurant.id)}
            key={restaurant.id}
            name={restaurant.name}
          />
        );
      })
    }    

此外,您将需要一些辅助方法来避免将this.references暴露于外界:

focusById(id) {
    this.references[id] && this.references[id].focus();
}

并特别注意清理对未安装元素的引用。否则,如果动态更改餐厅列表,则可能会发生内存泄漏(如果ref停留在this.references中,即使它已分离,它也会继续引用HTML元素)。实际需要取决于组件的使用方式。同样,一旦由于导航而将具有reference = {}的容器自身卸载,此内存泄漏将得到修复。