什么是Refs
Refs provide a way to access DOM nodes or React elements created in the render method.
Refs提供了一种在React中访问Dom节点的方式
Refs转发
Ref 转发允许某些组件 接收 ref,并将其向下传递(换句话说,“转发”它)给子组件。
ref会在componentDidMount或者componentDidUpdate生命周期触发前更新。当组件挂载componentDidMount时,React会将dom节点赋值给current,而当componentDidUpdate时,current的值被修改为null;
背景
在React单向数据流中,props是父子组件交互的唯一方式。
有些情况下,需要在数据流之外强行修改子组件(组件或者Dom元素),那么可以通过Refs来进行修改子组件。
访问 Refs
ref 的值根据节点的类型而有所不同:
- 当 ref 属性用于 HTML 元素时,构造函数中使用 React.createRef() 创建的 ref 接收底层 DOM 元素作为其current 属性。
- 当 ref 属性用于自定义 class 组件时,ref 对象接收组件的挂载实例作为其 current 属性。
- 不能在函数组件上使用Ref属性,因为函数组件没有实例。但是当你在函数组件内部时,可以通过ref来访问Dom节点或class组件。
创建 Refs
例子
-
当 ref 属性用于 HTML 元素时,JS 使用 React.createRef() 创建Refs
class MyComponent extends Component { private myRef = createRef() render() { return <div ref={this.myRef} /> } }
-
TS ts在jsx文件中有着非常优秀的类型推断,我们在一个
<div>
上增加了ref<div ref={this.myRef} />
,ts就推断出需要使用HTMLDivElement类型进行接收.
由于 React.createRef的定义function createRef<T>(): RefObject<T>
返回的RefObject是泛型;
解决方法:createRef<HTML自定义Element>()
import React from "react"; import { Component, createRef } from "react"; export default class TextInput extends React.Component { componentDidMount(){ console.log(this.textInput, 'chloe') } private textInput = createRef<HTMLInputElement>() textInputFocus = () => { //我们通过“current”来访问dom节点 this.textInput.current?.focus(); console.log(this.textInput.current, 'chloe') } render(){ return( <div> <input type="text" ref={this.textInput} /> <input type="button" value="focus this Input" onClick={this.textInputFocus} /> </div> ) } }
我们可以直接通过定义在ref上的current属性来访问这个node 节点
React文档是这样定义current的:当组件挂载componentDidMount时,React会将dom节点赋值给current,而当componentDidUpdate时,current的值被修改为null;
使用Refs实现兄弟组件传值
例子:TS 自定义Class组件 添加Ref
<DefalutLayout/>
父组件 包含两个子组件 HeaderPage和 IndexPage
现在要点击 <Headerpage/>
中的一个 图片按钮Button, 在<IndexPage/>
中 显示一个tips (提示页面)<TipsPage />
<IndexPage/>
定义显示tips的方法 showTip()- 父组件
<DefalutLayout/>
通过refs获取子组件<IndexPage/>
的showTip() - 父组件
<DefalutLayout/>
将showTip() 传给另一个子组件<Headerpage/>
import React, {createRef} from 'react';
import { PageHeader } from '../../components/HeaderPage';
import SpeechRetrieval from '../speechRetrieval/IndexPage';
export default class DefalutLayout extends React.Component {
tipsBtn = createRef<IndexPage>()
tips = () => {
//调用子组件
this.tipsBtn.current?.showTip()
};
render() {
return (
<div id="container">
<Layout>
<HeaderPage tips={this.tips}/>
<IndexPage ref={this.tipsBtn}></IndexPage>
</Layout>
</div>
);
}
}
子组件 IndexPage
//自定义子组件 IndexPage
export default class IndexPage extends React.Component {
state = { tipVisible:false }
//被调用方法
showTip = () =>{
this.setState({
tipVisible:true
})
}
render(){
const { tipVisible } = this.state;
return(
{ tipVisible && visible ? (<TipsPage />):(<p></p>) }
)
}
}
子组件 HeaderPage
import React from 'react';
import { Layout, Popconfirm } from 'antd';
const { Header } = Layout;
export function HeaderPage(props) {
return (
<Header className="header">
<div className="header-right-section">
<div onClick = {() => {props.tips()}}>
<img className="header-right-icon" src='/icon/tips.png' alt="tips"/>
</div>
</div>
</Header >
);
}