React系列:使用Ref

63 阅读2分钟

一、ref简介

  1. React中的ref属性可以帮助我们获取子组件的实例或者Dom对象,进而对子组件进行修改,是一个很方便的特性。
  2. 在传统类组件中,我们通过使用 React.createRef() 创建的,并通过 ref属性附加到 React 元素来使用。而随着hooks的越来越广泛的使用,我们有必要了解一下在函数式组件中,如何使用Ref?想要在函数式组件中使用Ref,我们必须先了解两个Api:useRefforwardRef

二、useRef

const refContainer = useRef(initialValue);

useRef返回一个可变的ref对象,其.current属性被初始化为传入的参数(initialValue)。返回的ref对象在整个生命周期内保持不变。

例子

const App = ()=> { 
    const inputEl = useRef(null);
    const onButtonClick = () => { 
    // `current`指向已挂载到 DOM 上的文本输入元素 
    inputEl.current.focus(); 
    }; 
return ( 
   <> 
      <input ref={inputEl} type="text" /> 
      <button onClick={onButtonClick}>Focus the input</button> 
   </> 
); 
}

效果

总结

点击button,先通过useRef创建一个ref对象inputEl,然后再将inputEl赋值给inputref,最后,通过inputEl.current.focus()就可以让input聚焦。 然后,我们再想下,如果input不是个普通的dom元素,而是个组件,该怎么办呢? 这就牵扯到另外一个api:forwardRef

三、forwardRef

const TextInput = forwardRef((props,ref) => { return <input ref={ref}></input> })
const App = ()=> { 
    const inputEl = useRef(null);
    const onButtonClick = () => { 
    // `current`指向已挂载到 DOM 上的文本输入元素 
    inputEl.current.focus(); 
    }; 
return ( 
   <> 
      <TextInput ref={inputEl} type="text" /> 
      <button onClick={onButtonClick}>Focus the input</button> 
   </> 
); 
}

总结

看到React.forwardRef 接受一个渲染函数,其接收 props 和 ref 参数并返回一个 React 节点。 这样我们就将父组件中创建的ref转发进子组件,并赋值给子组件的input元素,进而可以调用它的focus方法。 至此为止,通过useRef+forwardRef,我们就可以在函数式组件中使用ref了。当然,这篇文章还远不止如此,下面还要介绍两个重要的知识点useImperativeHandle回调Ref,结合上面两个api,让你的代码更加完美。

四、useImperativeHandle

有时候,我们可能不想将整个子组件暴露给父组件,而只是暴露出父组件需要的值或者方法,这样可以让代码更加明确。而useImperativeHandleApi就是帮助我们做这件事的。

useImperativeHandle(ref, createHandle, [deps])

useImperativeHandle 可以让你在使用 ref 时自定义暴露给父组件的实例值。

例子

const TextInput = forwardRef((props,ref) => { 
   const inputRef = useRef();  
   useImperativeHandle(ref, () => ({ 
      focus: () => { 
        inputRef.current.focus(); 
      } 
   })); 
return <input ref={inputRef} /> 
}) 

const App = ()=> { 
   const inputEl = useRef(null);
   const onButtonClick = () => { 
     // `current` 指向已挂载到 DOM 上的文本输入元素 
     inputEl.current.focus(); 
    }; 
return ( 
    <> 
      <TextInput ref={inputEl}></TextInput> 
      <button onClick={onButtonClick}>Focus the input</button> 
    </> 
); 
}

总结

这样,我们也可以使用current.focus()来事input聚焦。这里要注意的是,子组件TextInput中的useRef对象,只是用来获取input元素的,大家不要和父组件的useRef混淆了。

五、回调Ref