React高级指引之Refs and the DOM使用时机详解
作者:码农小菲
在典型的React数据流中,props是父组件与子组件交互的唯一方式。要修改一个子组件,你需要使用新的props来重新渲染它。但是,在某些情况下,你需要在典型数据流之外强制修改子组件
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 的绑定函数的方式可以避免上述问题,但是大多数情况下它是无关紧要的。
到此这篇关于React高级指引之Refs and the DOM使用时机详解的文章就介绍到这了,更多相关React Refs and the DOM内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!