具有基于getBoundingClientRect()问题的样式注入的React.cloneElement

时间:2019-06-07 10:15:50

标签: javascript reactjs

我正在尝试获得一种布局,在该布局中,容器组件指示子组件的style,或更具体地说,是子样式道具的width属性。

TL; DR:如何为所有渲染器(包括初始渲染器)基于父母的getBoundingClientRect()设置儿童道具。

安装容器组件后,我可以在容器组件上使用getBoundingClientRect()来计算所需的宽度,然后通过计算来运行它,但是对于初始渲染,结果是不存在的值,因为很明显,它仍然不在DOM中。

以下示例:

class Container extends Component {
    constructor(props) {
        super(props);
        this.containerRef = React.createRef();
        this.containerWidth = null;
        this.columnWidth= null;
    }

    componentDidMount() {
        this.containerWidth = this.containerRef.current.getBoundingClientRect().width;
        this.columnWidth = this.containerBaseWidth / this.props.columns;
    }

    injectChildrenWidth = () => {
        return React.Children.toArray(this.props.children)
            .map(el => {
                return React.cloneElement(
                    el,
                    { componentWidth: this.columnWidth }
                );
            });
    };

    render() {
        const Columns = this.injectChildrenWidth();
        return (
            <div ref={this.containerRef} >
                {Columns}
            </div>
        );
    }
}

允许父组件根据自己的getBoundingClientRect()宽度“指示”子组件的属性宽度的正确方法是什么?初始渲染永远不会为父对象提供值,因为它不在DOM中,我需要获取该值才能渲染子对象,因此我需要render()方法中的值。

我很确定整个概念是错误的,我应该研究一些不同的生命周期方法或方法,只是不知道在哪里/什么。

1 个答案:

答案 0 :(得分:1)

使用状态

class Container extends Component {
  constructor(props) {
    super(props);
    this.containerRef = React.createRef();
    this.state = {
      containerWidth: undefined,
      columnWidth: undefined
    };
  }

  componentDidMount = () => {
    let containerWidth = this.containerRef.current.getBoundingClientRect().width;
    let columnWidth = containerWidth / this.props.children.length;
    this.setState({ containerWidth, columnWidth });
  };

  injectChildrenWidth = () => {
    return React.Children.toArray(this.props.children).map(el => {
      return React.cloneElement(el, { componentWidth: this.state.columnWidth });
    });
  };

  render() {
    const Columns = this.injectChildrenWidth();
    return <div ref={this.containerRef}>{Columns}</div>;
  }
}