【问题标题】:React ref.current is null反应 ref.current 为空
【发布时间】:2019-08-10 10:07:51
【问题描述】:

我正在开发具有可变时间范围的议程/日历应用程序。要显示当前时间的一条线并显示已进行的约会的块,我需要计算给定时间范围内与一分钟对应的像素数。

例如:如果议程从早上 7 点开始,到下午 5 点结束,则总范围为 10 小时。假设日历主体的高度为 1000 像素。这意味着每小时代表 100 像素,每分钟代表 1,66 像素。

如果当前时间是下午 3 点。距离议程开始还有 480 分钟。这意味着显示当前时间的行应位于距日历主体顶部 796,8 像素 (480 * 1,66) 处。

计算没有问题,但获得了议程主体的高度。我正在考虑使用 React Ref 来获取高度,但出现错误:ref.current is null

下面是一些代码:

class Calendar extends Component {
    calendarBodyRef = React.createRef();

    displayCurrentTimeLine = () => {
        const bodyHeight = this.calendarBodyRef.current.clientHeight; // current is null
    }

    render() {
        return (
            <table>
                <thead>{this.displayHeader()}</thead>
                <tbody ref={this.calendarBodyRef}>
                    {this.displayBody()}
                    {this.displayCurrentTimeLine()}
                </tbody>
            </table>
        );
    }
}

【问题讨论】:

    标签: reactjs ref


    【解决方案1】:

    所以关于 refs 的问题是它们不能保证在第一次渲染时设置。您可以确定它们是在 componentDidMount 期间和之后设置的,因此您有两种前进方式。

    您可以使用回调样式 ref 并在此基础上设置状态。例如。您可以传入对 this.handleRef 之类的函数的引用,而不是将 ref 作为 prop 传递,它会在其中执行一些逻辑:

      handleRef = r => {
        this.setState({ bodyHeight: r.clientHeight})
        this.calendarBodyRef.current = r;
      };
    

    或者,您可以保留当前设置,但您必须将 clientHeight 位移动到生命周期函数,例如:

      componentDidMount() {
        this.setState({ bodyHeight: this.calendarBodyRef.current.clientHeight });
      }
    

    最终,您不能像这样立即读取 ref 的当前值,您必须在渲染后检查它,然后从状态中读取您的 bodyHeight

    【讨论】:

    • 我将使用 id 和 document.getElementById 来代替。我喜欢 React,但这是一个 React 设计问题。当我将组件从类切换到函数时,它莫名其妙地弹出。这种解决方法有什么害处?到目前为止,使用 getElementById 工作正常。
    • 我的意思是,如果你愿意,你完全可以这样做,但这样的设计可能会变得非常脆弱,因为你可能会遇到一些问题,比如渲染的组件的多个实例共享相同的 id 并且它可以使重构或泛化组件有点烦人。
    • 谢谢。我会坚持下去。肯定有权衡。我采用的方法不那么复杂,并且没有任何机会存在该组件的多个实例。因此,如果这是唯一可预见的危险,那么我对自己的决定感到满意。
    • @DanCancro 这不是 React 设计问题。在组件挂载之前,该元素甚至都不存在,而且也不可能存在,因此您将无法以这种方式查询它。在元素实际出现在页面上之后调用的函数中必须使用对元素的引用是有意义的。
    【解决方案2】:

    您可以使用 ref 回调函数。在这种情况下,您不需要使用“React-createRef()”。

    <tbody ref={this.calendarBodyRef}>
    ...
    calendarBodyRef = (e) => {
    console.log(e)
    }
    

    您将获得 DOM 元素,因此不需要使用“当前”。

    【讨论】:

      【解决方案3】:

      如果避免在组件状态下存储计算的身体高度是首选,那么另一种方法是引入第二个ref(即elementDisplayHeightRef),如下所示:

      class Calendar extends React.Component {
      
          /* Create a ref for the body */
          calendarBodyRef = React.createRef();
      
          /* Create a ref for element where height will be displayed */
          elementDisplayHeightRef = React.createRef();
      
          displayCurrentTimeLine = () => {
      
              /* Calculate body height from ref */
              const bodyHeight = this.calendarBodyRef.current.clientHeight;    
      
              /* Update display */
              this.elementDisplayHeightRef.current.innerText = `bodyHeight:${bodyHeight}`
          }
      
          render() {
              return (
                  <table>
                      <thead></thead>
                      <tbody ref={this.calendarBodyRef}>
                          <td><td>Some row</td></td>
                          {/* Bind display ref */ }
                          <tr><td ref={this.elementDisplayHeightRef}></td></tr>
                      </tbody>
                  </table>
              );
          }
      
          /* Add did mount life cycle hook, and trigger display of body height */
          componentDidMount() {
      
            this.displayCurrentTimeLine()
          }
      }
      

      此方法在componentDidMount() 生命周期挂钩期间调用displayCurrentTimeLine()(它本身在第一个render() 之后调用)以确保refs 在组件逻辑与@987654328 中的它们交互之前完全初始化@。

      希望有帮助!

      【讨论】:

        【解决方案4】:

        如果您使用 react-redux 并将您的组件包装在 connect 函数中,那么您需要像这样传递第四个参数,即 forwardRef。

        connect(mapStateToProps, mapDispatchToProps, null, {forwardRef: true})
        

        希望对你有帮助。

        【讨论】:

        • 是的,很有帮助
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-08-13
        • 2018-07-27
        • 2020-03-07
        • 2019-01-31
        • 2019-04-24
        • 2017-10-23
        • 2020-07-10
        相关资源
        最近更新 更多