Why doesn't const { innerRef, …props } = this.props; grab a refrence to this.props.innerRef in react ref forwarding?

huangapple go评论78阅读模式
英文:

Why doesn't const { innerRef, ...props } = this.props; grab a refrence to this.props.innerRef in react ref forwarding?

问题

在React中,使用ref forwarding(引用转发)时,你可以使用innerRef来捕获传递给组件的ref。在你提供的代码示例中,你尝试了两种不同的方法。

在第一种方法中,你创建了一个带有innerRef属性的组件FancybtnWthRef,然后在Fancybtn组件内部尝试将innerRef属性绑定到按钮的ref上。这种方式不起作用,因为你没有正确地将innerRef传递给Fancybtn组件。这个问题可以通过以下方式修复:

class Fancybtn extends React.Component {
  constructor(props) {
    super(props);
    const { innerRef, ...props2 } = this.props;
    console.log(innerRef, this.props.innerRef);
  }

  render() {
    return (
      <button className="fancy-btn" ref={this.props.innerRef} {...this.props2}>
        {this.props.txt}
      </button>
    );
  }
}

在第二种方法中,你直接使用this.props.innerRef来引用按钮的ref,这种方式有效,因为你直接使用了this.props.innerRef,而不是通过解构赋值。

总之,解构赋值不会像你期望的那样在这种情况下工作,因为它不会创建一个实时绑定到this.props的对象。相反,你需要直接使用this.props.innerRef来访问innerRef属性。

英文:

After reading forwarding refs from react legacy docs and following the examples from the SO post on using ref forwarding on classes, I tried to create a working example as following:

<!-- begin snippet: js hide: false console: true babel: true -->

<!-- language: lang-js -->

class Card extends React.Component {

  constructor(props) {
    super(props);
    this.myRef = React.createRef();
    //after three seconds focus myRef
    setTimeout(() =&gt; {
      console.log(this.myRef);
      this.myRef.current.focus();
    }, 3000);
  }

  render() {
    return &lt;FancybtnWthRef ref={this.myRef} txt=&quot;random&quot;/&gt;;
  }
}

//Fancybtn class based componenet with ref forwarding

class Fancybtn extends React.Component {
  constructor(props) {
    super(props);
    const { innerRef, ...props2 } = this.props;
    console.log(innerRef, this.props.innerRef); //doesn&#39;t get live binding to this.props.innerRef
  }

  render() {
    return (
      &lt;button className=&quot;fancy-btn&quot; ref={this.innerRef} {...this.props2}&gt;
        {this.props.txt}
      &lt;/button&gt;
    );
  }
}

const FancybtnWthRef = React.forwardRef((props, ref) =&gt; {
  return &lt;Fancybtn {...props} innerRef={ref} /&gt;;
});




ReactDOM.render(
  &lt;Card /&gt;,
  document.getElementById(&#39;root&#39;)
);

<!-- language: lang-html -->

&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js&quot;&gt;&lt;/script&gt;

&lt;div id=&quot;root&quot;&gt;&lt;/div&gt;

<!-- end snippet -->

On the other hand, if I grab the this.props.innerRef object directly for button, then it works:

<!-- begin snippet: js hide: false console: true babel: true -->

<!-- language: lang-js -->

class Card extends React.Component {

  constructor(props) {
    super(props);
    this.myRef = React.createRef();
    //after three seconds focus myRef
    setTimeout(() =&gt; {
      console.log(this.myRef);
      this.myRef.current.focus();
    }, 3000);
  }

  render() {
    return &lt;FancybtnWthRef ref={this.myRef} txt=&quot;random&quot;/&gt;;
  }
}

//Fancybtn class based componenet with ref forwarding

class Fancybtn extends React.Component {
  constructor(props) {
    super(props);
    const { innerRef, ...props2 } = this.props;
    console.log(innerRef, this.props.innerRef);
  }

  render() {
    return (
      &lt;button className=&quot;fancy-btn&quot; ref={this.props.innerRef} {...this.props2}&gt;
        {this.props.txt}
      &lt;/button&gt;
    );
  }
}

const FancybtnWthRef = React.forwardRef((props, ref) =&gt; {
  return &lt;Fancybtn {...props} innerRef={ref} /&gt;;
});





ReactDOM.render(
  &lt;Card /&gt;,
  document.getElementById(&#39;root&#39;)
);

<!-- language: lang-html -->

&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js&quot;&gt;&lt;/script&gt;

&lt;div id=&quot;root&quot;&gt;&lt;/div&gt;

<!-- end snippet -->

In plain javascript destructuring gets live binding of objects as following:

var obj = {x:1, obj2: {y: 33}}
const {x, obj2} = obj;
obj2.y = 44;
cconsole.log(obj.obj2.y); //gives 44

Using the same argument why doesn't const { innerRef, ...props } = this.props; grab the actual this.props.innerRef for the button?

答案1

得分: 2

The code segment const { innerRef, ...props2 } = this.props; correctly extracts the innerRef property from props. However, it creates two local variables and does not set the actual innerRef property on the instance itself. Therefore, this.innerRef remains undefined, and passing it as a ref to the <button> has no effect. Unlike some other languages like Java, accessing a variable without using this does not look up that variable in the fields of the enclosing class instance.

To make it work, you need to manually assign the innerRef to the instance like this:

this.innerRef = innerRef;

Alternatively, if you want to destructure the properties onto this, you can rename the property as follows:

({ innerRef: this.innerRef, ...this.props2 } = this.props);
英文:

const { innerRef, ...props2 } = this.props; does correctly get the innerRef property from props. However, this creates two local variables. It does not set the actual innerRef property on the instance itself. Thus, this.innerRef is undefined and passing that as the ref to the &lt;button&gt; has no effect. Note that unlike other languages like Java, accessing a variable without using this will not attempt to look up that variable in the fields of the enclosing class instance.

You would have to manually assign the innerRef to the instance to see it work:

this.innerRef = innerRef;

Or, to destructure the properties onto this, you can rename the property like so:

({ innerRef: this.innerRef, ...this.props2 } = this.props);

huangapple
  • 本文由 发表于 2023年6月4日 22:45:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/76400954.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定