![refs](https://tva1.sinaimg.cn/large/0081Kckwgy1gkkcm1nzswj30zk0k075h.jpg)
「问题」
落日余晖🌞舒云剩影☁️的旁晚
小白:师父,React里面的Refs有什么用啊?
乐闻:先考你一个问题,现在有一个表单,页面加载完成时第一个input框自动获取焦点,不需要人为选中,应该怎么实现?
小白:直接给 input标签加上autoFocus属性呗,例如<input autoFocus="autofocus"/>
乐闻:emm... 这种方式也可以,还有其他的实现方式没?
小白:如果使用jquery的话就好了,可以直接获取到input标签实例,然后调用它的focus()方法就可以实现自动聚焦了。React的话不知道怎么弄。
乐闻:React也提供了我们访问DOM节点的能力,接下来我详细的跟你说说这个refs属性。
「官方定义」
Refs 提供了一种方式,允许我们访问 DOM 节点或在 render 方法中创建的 React 元素。
备注:1. DOM节点就是JSX里的div,input等原生标签。
2. React元素就是 我们创建的React组件,比如class组件,函数组件。
React推崇「状态决定视图」,页面怎么展示由数据状态控制。但是有些时候这样操作并不是很便捷,甚至不能实现理想功能。
React提供了Refs帮助开发者可以直接操作DOM节点,就像jquery时代一样,直接操作DOM,简单明了。但是官方建议:勿过度使用 Refs。 意思是能不用就不用,除非实在没有办法了。
「使用场景」
-
管理焦点,文本选择或媒体播放。 -
触发强制动画。 -
集成第三方 DOM 库。
「代码实操」
React 组件分为两种 Class组件 + Function组件。两种组件使用Refs的方式也各不相同。
下面列表各种场景下的使用方式,如果举例没有覆盖到的,欢迎留言补充👏
-
操作原生DOM
-
class组件
-
React.createRef( 推荐)
import React, { Component } from "react";
class RefsDeme extends Component {
constructor(props) {
super(props);
this.state = {};
this.inputRef = React.createRef();
}
componentWillMount() {
console.log("componentWillMount->inputRef:", this.inputRef);
}
componentDidMount() {
console.log("componentDidMount->inputRef:", this.inputRef);
this.inputRef.current.focus();
}
render() {
return (
<div>
姓名: <input ref={this.inputRef} />
</div>
);
}
}
export default RefsDeme;-
回调函数方式
import React, { Component } from "react";
class RefsDeme extends Component {
constructor(props) {
super(props);
this.state = {};
this.inputRef = null;
}
componentWillMount() {
}
componentDidMount() {
this.inputRef.focus();
}
render() {
return (
<div>
姓名:{" "}
<input
ref={(ref) => {
this.inputRef = ref;
}}
/>
</div>
);
}
}
export default RefsDeme;-
string方式( 不推荐,了解即可)
import React, { Component } from "react";
class RefsDeme extends Component {
constructor(props) {
super(props);
this.state = {};
}
componentWillMount() {
console.log("componentWillMount->inputRef:", this.refs.inputRef);
}
componentDidMount() {
console.log("componentDidMount->inputRef:", this.refs.inputRef);
this.refs.inputRef.focus();
}
render() {
return (
<div>
姓名: <input ref='inputRef' />
</div>
);
}
}
export default RefsDeme;-
function组件
因为Function组件不存在this,所以function组件不能通过class组件的方式来操作refs。Function组件使用refs,需要用到React Hooks。
import React, { useRef, useEffect } from "react";
export default function FunctionRef() {
const inputRef = useRef();
useEffect(() => {
inputRef.current.focus();
}, []);
return (
<div>
FunctionRef: <input ref={inputRef} />
</div>
);
} -
-
操作React组件
-
class组件
// ClassComponent.js
import React, { Component } from "react";
export default class Class extends Component {
onCheck = (type) => {
alert("type:" + type);
};
render() {
return <div onClick={this.onCheck.bind(this, "child")}>Class</div>;
}
}
// RefsDemo.js
import React, { Component } from "react";
import ClassComponent from "./ClassComponent";
class RefsDeme extends Component {
constructor(props) {
super(props);
this.state = {};
this.classRef = React.createRef();
}
componentWillMount() {
console.log("componentWillMount->classRef:", this.classRef);
}
componentDidMount() {
console.log("componentDidMount->classRef:", this.classRef);
}
render() {
return (
<ClassComponent ref={this.classRef} />
);
}
}
export default RefsDeme;备注:父组件可以获取自组件实例并调用自组件中定义的方法
-
function组件
默认情况下,不能在函数组件上使用
ref
属性,因为它们没有实例直接对 普通的函数组件使用 ref 属性时会 Warning
如果需要操作Function组件的refs,需要通过React.forwardRef高阶组件包裹一层。
// FunctionComponent.js
import React, { useImperativeHandle } from "react";
export default React.forwardRef(function Function(props, ref) {
const onCheck = (type) => {
alert("type:" + type);
};
//需要把什么属性或者方法传给副组件,通过useImperativeHandle返回
useImperativeHandle(ref, () => ({
onCheck: onCheck.bind(null, "father"),
}));
return <div onClick={onCheck.bind(null, "child")}>Function</div>;
});
// RefsDemo.js
import React, { Component } from "react";
import FunctionComponent from "./FunctionComponent";
import ClassComponent from "./ClassComponent";
class RefsDeme extends Component {
constructor(props) {
super(props);
this.state = {};
this.functionRef = React.createRef();
}
componentWillMount() {
console.log("componentWillMount->functionRef:", this.functionRef);
}
componentDidMount() {
console.log("componentDidMount->functionRef:", this.functionRef);
}
render() {
return (
<div>
<FunctionComponent ref={this.functionRef} />
<button
onClick={() => {
this.functionRef.current.onCheck();
}}>
调用自组件方法
</button>
</div>
);
}
}
export default RefsDeme;点击自组件触发onCheck方法
点击父组件按钮触发onCheck方法
-
总结:
ref
提供了一种对于react标准的数据流不太适用的情况下组件间交互的方式, 但是在大多数情况下应该使用react响应数据流那种方式,不要过度使用ref。
普通人还在犹豫的时候,好看的人已经一键三连咯~👋👋👋
「公众号」:乐闻世界