落日余晖舒云剩影☁️的旁晚
小白:师父,React里面的Refs有什么用啊?
乐闻:先考你一个问题,现在有一个表单,页面加载完成时第一个input框自动获取焦点,不需要人为选中,应该怎么实现?
小白:直接给 input标签加上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。 意思是能不用就不用,除非实在没有办法了。
React 组件分为两种 Class组件 + Function组件。两种组件使用Refs的方式也各不相同。
下面列表各种场景下的使用方式,如果举例没有覆盖到的,欢迎留言补充
操作原生DOM
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 (
姓名:
);
}
}
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 (
姓名:{" "}
ref={(ref) => {
this.inputRef = ref;
}}
/>
);
}
}
export default RefsDeme;
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 (
姓名: 'inputRef' />
);
}
}
export default RefsDeme;
因为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 (
FunctionRef:
);
}
操作React组件
// ClassComponent.js
import React, { Component } from "react";
export default class Class extends Component {
onCheck = (type) => {
alert("type:" + type);
};
render() {
return "child")}>Class;
}
}
// 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 (
);
}
}
export default RefsDeme;
备注:父组件可以获取自组件实例并调用自组件中定义的方法
默认情况下,不能在函数组件上使用
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 "child")}>Function;
});
// 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 (
);
}
}
export default RefsDeme;
点击自组件触发onCheck方法
点击父组件按钮触发onCheck方法
总结:
ref
提供了一种对于react标准的数据流不太适用的情况下组件间交互的方式, 但是在大多数情况下应该使用react响应数据流那种方式,不要过度使用ref。
普通人还在犹豫的时候,好看的人已经一键三连咯~
「公众号」:乐闻世界