react(精读官方文档) -高级指引 - Refs and the DOM

Refs and the DOM

  • Refs 提供了一种方式,允许我们访问 DOM 节点或在 render 方法中创建的 React 元素
  • 在某些情况下,需要在典型数据流之外强制修改子组件。被修改的子组件可能是一个 React 组件的实例,也可能是一个 DOM 元素。

何时使用 Refs

  • 管理焦点,文本选择或媒体播放
  • 触发强制动画
  • 集成第三方 DOM 库

勿过度使用 Refs

创建 Refs

  • React.createRef()创建
  • 通过 ref 属性附加到 React 元素
class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();
  }
  render() {
    return <div ref={this.myRef} />;
  }
}

访问 Refs

  • 在 ref 的 current 属性中被访问

    const node = this.myRef.current;
    
  • 为 DOM 元素添加 ref

    class CustomTextInput extends React.Component {
      constructor(props) {
        super(props);
        // 创建一个 ref 来存储 textInput 的 DOM 元素
        this.textInput = React.createRef();
        this.focusTextInput = this.focusTextInput.bind(this);
      }
    
      focusTextInput() {
        // 直接使用原生 API 使 text 输入框获得焦点
        // 注意:我们通过 "current" 来访问 DOM 节点
        this.textInput.current.focus();
      }
    
      render() {
        // 告诉 React 我们想把 <input> ref 关联到
        // 构造器里创建的 `textInput` 上
        return (
          <div>
            <input
              type="text"
              ref={this.textInput} />
            <input
              type="button"
              value="Focus the text input"
              onClick={this.focusTextInput}
            />
          </div>
        );
      }
    }
    
  • 为 class 组件添加 Ref

      class AutoFocusTextInput extends React.Component {
        constructor(props) {
          super(props);
          this.textInput = React.createRef();
        }
      
        componentDidMount() {
          this.textInput.current.focusTextInput();
        }
      
        render() {
          return (
            <CustomTextInput ref={this.textInput} />
          );
        }
      }
    

    不能在函数组件上使用 ref 属性,如果要在函数组件中使用 ref,你可以使用 forwardRef(可与 useImperativeHandle 结合使用),或者可以将该组件转化为 class 组件

    function CustomTextInput(props) {
       // 这里必须声明 textInput,这样 ref 才可以引用它
       const textInput = useRef(null);
     
       function handleClick() {
         textInput.current.focus();
       }
     
       return (
         <div>
           <input
             type="text"
             ref={textInput} />
           <input
             type="button"
             value="Focus the text input"
             onClick={handleClick}
           />
         </div>
       );
     }
    

将 DOM Refs 暴露给父组件

  • 不建议暴露 DOM 节点

回调 Refs

  • 另一种设置 refs 的方式,称为“回调 refs”.
  • 能助你更精细地控制何时 refs 被设置和解除
  • 不同于传递 createRef() 创建的 ref 属性,你会传递一个函数。这个函数中接受 React 组件实例或 HTML DOM 元素作为参数,以使它们能在其他地方被存储和访问
        class CustomTextInput extends React.Component {
         constructor(props) {
           super(props);
       
           this.textInput = null;
       
           this.setTextInputRef = element => {
             this.textInput = element;
           };
       
           this.focusTextInput = () => {
             // 使用原生 DOM API 使 text 输入框获得焦点
             if (this.textInput) this.textInput.focus();
           };
         }
       
         componentDidMount() {
           // 组件挂载后,让文本框自动获得焦点
           this.focusTextInput();
         }
       
         render() {
           // 使用 `ref` 的回调函数将 text 输入框 DOM 节点的引用存储到 React
           // 实例上(比如 this.textInput)
           return (
             <div>
               <input
                 type="text"
                 ref={this.setTextInputRef}
               />
               <input
                 type="button"
                 value="Focus the text input"
                 onClick={this.focusTextInput}
               />
             </div>
           );
         }
       }
    // 在上面的例子中,Parent 把它的 refs 回调函数当作 inputRef props 传递给了 CustomTextInput,而且 CustomTextInput 把相同的函数作为特殊的 ref 属性传递给了 <input>。结果是,在 Parent 中的 this.inputElement 会被设置为与 CustomTextInput 中的 input 元素相对应的 DOM 节点
    
    • 如果 ref 回调函数是以内联函数的方式定义的,在更新过程中它会被执行两次,第一次传入参数 null,然后第二次会传入参数 DOM 元素。这是因为在每次渲染时会创建一个新的函数实例,所以 React 清空旧的 ref 并且设置新的。通过将 ref 的回调函数定义成 class 的绑定函数的方式可以避免上述问题,但是大多数情况下它是无关紧要的。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值