在子支架上访问父组件的子组件中的Ref

时间:2019-04-03 00:22:31

标签: javascript reactjs

我具有以下父/子组件。最初渲染Child组件后,我需要滚动到顶部。

import React, {Component} from 'react';
import Child from "./Child";

class Parent extends Component {

  render() {
    return (
      <div>
        <div ref={topDiv => {
          this.topDiv = topDiv;
        }}/>
        <Child
          topDiv={this.topDiv}
        />
      </div>
    );
  }
}

export default Parent;
import React, {Component} from 'react';

class Child extends Component {

  componentDidMount() {
    this.scrollToTop();
  }

  // componentWillReceiveProps(nextProps, nextContext) {
  //   nextProps.topDiv.scrollIntoView();
  // }

  scrollToTop() {
    this.props.topDiv.scrollIntoView();
  }

  render() {
    return (
      <div style={{height: '500rem'}}>
        Long Child
      </div>
    );
  }
}

export default Child;

使用此方法,我收到错误消息:

  

TypeError:无法读取未定义的属性'scrollIntoView'

我认为这是因为调用componentDidMount时还没有收到道具,所以topDiv为空/未定义。

如果我使用componentWillReceiveProps,如注释部分所示,则可以正常工作。但由于以下原因,我无法使用它:
1.已弃用。
2.我认为每次收到道具时都会调用它。因此,我想我需要保留一个变量以了解是否是第一次收到道具?

我不能使用componentDidUpdate,因为documentation表示“ 初始渲染未调用此方法。”。

渲染组件后首次收到道具时该怎么做?

3 个答案:

答案 0 :(得分:1)

绝对应该在componentDidMount中提供道具。

这似乎可能是由于React生命周期中有些混乱。

在您的父母中,大约在安装Child的同时,在渲染器中提供了ref回调。根据{{​​3}}:

  

React将在组件装入时使用DOM元素调用ref回调,而在组件卸载时使用null进行调用。保证在componentDidMount或componentDidUpdate触发之前,引用是最新的。

但是,componentDidMount个孩子将在其父母componentDidMount之前解雇,因此,这种保证并不意味着Parent的{​​{1}}将在{ {1}}呼叫this.topDiv。 (而且,进一步考虑,它绝对不保证在作为道具提供给Child之前会被定义。)

在您的父母中,您可以尝试类似的

componentDidMount

这将确保在安装Child之前设置您的参考。 componentDidMount() { this.setState({ divSet: true }); } render() { let child = null; if (this.state.divSet) { child = <Child topDiv={this.topDiv} /> } return ( <div> <div ref={topDiv => { this.topDiv = topDiv; }}/> {child} </div> ); } 专门用于在设置ref时强制父级重新呈现。

答案 1 :(得分:1)

根据定义,您正在尝试做的事情是不可能的!当你说

  

我需要在子组件最初开始时滚动到顶部   呈现。

您是说父母的右上角吗?

但是这里的关键细节是

  

您的孩子完成渲染后,您的父母尚未   被渲染!没有顶部可以滚动到Yet !!


组件的生命周期

这是组件的典型生命周期流

  1. constructor()
  2. componentWillMount()
  3. render()
  4. componentDidMount()

当涉及到亲子关系时

  1. [Parent] constructor()
  2. [Parent] componentWillMount()
  3. [父母] render()
    1. [Child] constructor()
    2. [Child] componentWillMount()
    3. [Child] render()
    4. [Child] componentDidMount()-父级不存在
  4. [Parent] componentDidMount()

还简要说明了新添加的生命周期方法,代替了componenWillRecieveProps

  

getDerivedStateFromProps(道具,状态)

     

getDerivedStateFromProps在调用渲染之前被调用   初始安装和后续更新上的方法。这应该   返回一个对象以更新状态,或者返回null则不更新任何内容。


  

所以最好的选择是在不被允许的情况下调用滚动条   组件componentDidMount,您可以在其中访问其引用。

如果仍然确定要在子组件中执行此操作,则必须将 getDerivedStateFromProps 与状态标记结合使用,以检测您是否已至少滚动到顶部一次。总体上来说这可能有点效率和肮脏。

请查看here,以获取组件生命周期的凉爽流程图,以了解其清晰性!

答案 2 :(得分:0)

this.scrollToTop绑定到constructor中的类组件:

class Child extends Component {
  constructor() {
    this.scrollToTop = this.scrollToTop.bind(this);
  }
  ...rest of your component code