使用 React.createRef 时 current 始终为 null

current is always null when using React.createRef

我正在尝试 this

我一定是漏掉了什么,但我不明白为什么在这个例子中 current 总是 null

class App extends React.PureComponent {
  constructor(props) {
    super(props);
    this.test = React.createRef();
  }
  render() {
    return <div className="App">current value : {this.test.current + ""}</div>;
  }
}

你可以查看我的测试用例here

您缺少 ref={this.test} 道具。

return (
  <div className="App" ref={this.test}>
    current value : {this.test.current + ""}
  </div>
);

因为您忘记将 ref 分配给某些 dom 元素。你只是在创造它。

这样写:

class App extends React.PureComponent {
  constructor(props) {
    super(props);
    this.test = React.createRef();
  }

  handleClick = () => alert(this.test.current.value)

  render() {
    return (
      <div className="App">
        <input ref={this.test} />
        <button onClick={this.handleClick}>Get Value</button>
      </div>
    )
  }
}

Working Example.

React.createRef() 是异步的,因此如果您尝试访问 componentDidMount 中的 ref,它将 return 为 null,之后 return 您正在引用的组件的属性.

componentDidMount(): void {
      if (this.viewShot && this.viewShot.current) {
          this.viewShot.current.capture().then((uri) => {
        console.log('do something with ', uri);
          });
      }
  }

这是在此上下文中使用 React.createRef() 的正确方法。

我知道这不是 OP 问题的解决方案,但对于那些来自 google 搜索的人来说,ref.current 可以为 null 的一种方式是,如果正在附加的 ref 是一个连接的组件。就像 react-redux connect 或 withRouter 一样。对于 react-redux 解决方案是在第四个选项中传递 forwardRef:true 以连接。

<div ref={this.test}>

您必须将 ref 道具分配给您的 DOM 元素。 在这种情况下,您必须将 ref 分配给 div element

在以下情况下可能会发生这种情况:

  • 您忘记将 ref 传递给组件,即问题中的 this.test

<Component ref={this.test} />

  • 您正在使用 Redux,其中传递 ref 道具的组件由 connect 方法包装,因此this.test.current 会 return null 因为它指向 Redux 包装器,使这种组件工作 make forwardRef: true

i.e: connect(mapStateToProps, mapDispatchToProps, null, {forwardRef: true})(Component)

  • 如果您同时使用 withRouterconnect,那么在这里您将使用 两个 而不是 一个 wrappersthis.test.current 显然会 return null,为了克服这个问题确保 withRouter 包装 connect

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

然后

<Component wrappedComponentRef={ref => this.test = ref} />

wrappedComponentRef 是一个 prop,用于使包装组件像 forwardRef: true 一样可用,您可以在文档 here

中找到它

在 React 17.0.2 版本中,refs 和它是异步的发生了变化。像这样的代码在更新后停止正常工作:

import {useRef} from 'react';
import './kind.css'

const Kind = ({prop}) => {

    // defining the ref
    const kindRef = useRef('')
    
    // print the ref to the console
    console.log(kindRef)


    return (
    <div ref={kindRef} className="kind-container" >
        <div className="kind" data-kind='drink'>Drink</div>
        <div className="kind" data-kind='sweet'>Sweet</div>
        <div className="kind" data-kind='lorem'>lorem</div>
        <div className="kind" data-kind='ipsum'>ipsum</div>
        <div className="kind" data-kind='ipsum' >food</div>
    </div>
    );
}

export default Kind;

初始化 ref 后,需要一些时间才能将其分配给 dom。 Javascript,作为一种同步语言,不等待 ref 初始化并直接跳到日志。

要解决这个问题,我们需要像这样使用 useEffect

import { useRef, useEffect} from 'react';
import './kind.css'

const Kind = ({prop}) => {

    // defining the ref
    const kindRef = useRef('')
    
    // using 'useEffect' will help us to do what ever you want to your ref varaible,
    // by waiting to letting the elements to mount:'mount means after the elements get inserted in the page' and then do what you want the ref
    useEffect(()=>{

        // print the ref to the console
        console.log(kindRef)        

    })


    return (
    <div ref={kindRef} className="kind-container" >
        <div className="kind" data-kind='drink'>Drink</div>
        <div className="kind" data-kind='sweet'>Sweet</div>
        <div className="kind" data-kind='lorem'>lorem</div>
        <div className="kind" data-kind='ipsum'>ipsum</div>
        <div className="kind" data-kind='ipsum' >food</div>
    </div>
    );
}

export default Kind;

useEffect 等待将 ref 分配给 DOM 元素,然后运行分配给它的函数。

如果你在useCallback(或其他钩子)中使用ref,请记住将ref添加到依赖项中:

const doSomething = useCallback(() => {
 ref.current?.doIt();
}, [ref]);