React ref.current为null

时间:2019-03-19 19:14:18

标签: reactjs ref

我正在使用时间范围可变的议程/日历应用程序。要显示当前时间的一行并显示已约会的块,我需要计算给定时间范围内一分钟对应多少像素。

因此,例如:如果议程从早上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>
        );
    }
}

4 个答案:

答案 0 :(得分:3)

因此,关于ref的事情是不能保证在首次渲染时设置它们。您可以确定它们是在componentDidMount期间和之后设置的,因此有两种前进的方式。

您可以使用回调样式ref并基于此设置状态。例如。您可以将对诸如this.handleRef之类的函数的引用传递给它,而不用像prop那样传递引用。

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

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

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

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

答案 1 :(得分:1)

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

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

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

答案 2 :(得分:0)

如果最好避免以组件状态存储计算出的身高,则另一种方法是像这样引入第二个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()
    }
}

此方法会在displayCurrentTimeLine()生命周期挂钩期间调用componentDidMount()(其本身在第一个render()之后被调用),以确保在refs之前完全初始化两个displayCurrentTimeLine()组件逻辑在es.mysite.com中与它们交互。

希望有帮助!

答案 3 :(得分:0)

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

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

希望对您有所帮助。