Refs 和 DOM
Refs提供了一种在render方法中创建DOM 节点或React 元素的方式
在常规的 React 数据流中,props 是父组件与子组件交互的唯一方式。要修改子元素,你需要用新的props去重新渲染子元素。
Refs:强制修改子元素。被修改的子元素可以是
React组件实例(类组件实例),或者是一个DOM 元素,不能使函数组件
何时使用 Refs
- 处理
focus、文本选择或者媒体播放 - 触发强制
动画 - 集成第三方
DOM库 - 如果可以通过声明式实现,就尽量避免使用
refs
不要过度使用 Refs
能使用
状态提升运用state改变组件状态,不要使用refs来更新组件
创建 Refs: React.createRef()
使用
React.createRef()创建refs,通过ref属性来获得 子元素。当构造组件时,
refs通常被赋值给实例的一个属性,这样你可以在组件中任意一处使用它们.
1 | class MyComponent extends React.Component { |
访问 Refs: ref.current
ref属性被传递给一个render函数中的元素时,可以使用ref中的current属性对节点的引用进行访问。
1 | const node = this.myRef.current; |
ref的值取决于节点的类型:
- 当
ref属性被用于一个普通的HTML元素时,React.createRef()将接收底层DOM 元素作为它的current属性以创建ref。 - 当
ref属性被用于一个自定义类组件时,ref对象将接收该组件已挂载的实例作为它的current。 不能在函数式组件上使用ref属性,因为它们没有实例
React组件在加载时将DOM元素传入ref的回调函数,在卸载时则会传入null。在componentDidMount或componentDidUpdate这些生命周期回调之前执行ref回调
在 DOM 元素上添加 Ref
1 | class CustomTextInput extends React.Component { |
类(Class)组件 添加Ref
包装上面的
CustomTextInput,来模拟挂载之后立即被点击:使用ref来访问自定义组件,并手动调用它的focusTexInput方法
这种方法仅对以类(class)声明的 CustomTextInput 有效
当ref是类组件实例时,可以直接获取实力上的属性及方法
1 | //上面的CustomTextInput组件不再重复写 |
Refs 与 函数式组件
不能在函数式组件上使用 ref 属性,因为它们没有实例,如果需要使用 ref ,就需要将组件转化成 类(class)组件,就像需要 生命周期方法 或者 state 一样。
1 | //错误 |
但是可以 在函数式组件内部使用 ref 来引用一个 DOM 元素或者 类(class)组件:ref={(input) => { textInput = input; }}input就是个形参 代表当前元素,可以是任何形参名
1 | function CustomTextInput(props) { |
对父组件暴露 DOM 节点
通常
不建议从父组件访问子节点的 DOM 节点,因为它会破坏组件的封装,但偶尔也可用于触发焦点或测量子 DOM 节点的大小或位置可以像上边 “类(Class) 组件添加 Ref”章节那样 先通过
refs获得自定义组件,然后在组件内添加refs来实现缺陷:
只能获取组件实例而不是 DOM 节点。并且,它还在函数式组件上无效
通常通过“Ref转发”实现对父组件暴露DOM节点
回调 Refs(能用 createRef不用回调refs)ref={element=>this.textInput = element}
“回调 ref”,更加细致地控制何时 ref 被设置和解除。
不同于传递createRef()创建的 ref 属性,它会传递一个函数。这个函数接受React 组件的实例或HTML DOM 元素作为参数,以存储它们并使它们能被其他地方访问。
回调ref``不需要通过 current属性访问,直接this.textInput.focus();
1 | class CustomTextInput extends React.Component { |
在组件间通过props传递回调形式的 refs(父组件获取子组件元素)
Parent通过props将ref 回调函数作为inputRef属性传递给CustomTextInput组件,然后CustomTextInput组件通过ref属性将其传递给<input>元素。最终,
Parent中的this.inputElement将被设置为与CustomTextIput组件中的<input>元素相对应的DOM 节点
1 | function CustomTextInput (props) { |
1 | class Parent extends React.Component{ |
转发 Refs
Ref转发是一种自动将ref通过组件传递给子组件的技术
Ref转发是一种选择性加入的功能,可让某些组件接收他们收到的ref,并将其向下传递(换句话说,“转发”)给子组件。
React.forwardRef((props,ref)=>())接收props,ref作为参数第二个
ref参数仅在使用 React.forwardRef 调用定义组件时才存在,常规函数或类组件不接收ref参数
Ref转发不限于 DOM 组件。也可以将refs转发给类组件实例。
FancyButton 使用 React.forwardRef 来获取传递给它的 ref , 然后将其转发给它渲染的的 DOM button:
1 | //3. ref转发 |
上面示例的步骤:
我们通过调用
React.createRef创建一个React ref并将其分配给ref变量。通过将
ref变量传递给指定ref为JSX属性的<FancyButton ref={ref}>。
React将ref传递给forwardRef中的(props, ref) => ... 函数作为第二个参数。我们将这个
ref参数转发到指定ref为JSX属性的<button ref = {ref}>。当附加
ref时,ref.current将指向<button>DOM节点。
将父组件通过createRef创建的Ref通过props传递给子组件,子组件将传递过来的ref绑定在其元素上也能实现 ref转发
也可以:
1 | function CustomTextInput(props) { |
当使用
HOC扩展组件时,建议使用React的forwardRef函数 将ref转发到 包装组件上第三方
HOC没有实现ref转发, 上述模式仍然可以用作后备。