在react 中主要时操作数据进行操作,但是会有许多情况下我们还是需要获取dom,所以我们会用到ref
ref
ref的作用
Ref属性用来获取DOM 元素的节点和获取子组件的实例
我们先来看在class 组件中的ref
- refs时使用React.create()创建的,并通过ref属性附加到React 元素中,在构建组件时,通常将Refs 分配给属性实例,以便在整个组件中华引用它们
- 当ref被传递给render中的元素时,改节点可以在ref的current属性中被访问
- React 会在组件挂载时给current属性传入DOM元素,并在卸载时传入null 值。
- ref会在componentDidMOunt或者componentDidUpdate生命周期的钩子函数触发
获取DOM元素节点:
import React, { Component, createRef} from "react";
class App extends Component {
constructor(props) {
super(props);
this.h1Ref = createRef();
}
componentDidMount() {
console.log("React.createRef()");
console.log(this.h1Ref.current);
}
render() {
return <h1 ref={this.h1Ref}>Hello World!</h1>;
}
}
export default App;
结果
获取子组件实例
import React, { Component, createRef } from "react";
class App extends Component {
constructor(props) {
super(props);
this.childRef = createRef();
}
componentDidMount() {
console.log("React.createRef()");
console.log(this.childRef.current);
this.childRef.current.handleLog();
}
render() {
return (
<div>
<h1>Hello World!</h1>
<Child ref={this.childRef} count="1" />
</div>
);
}
}
class Child extends Component {
handleLog = () => {
console.log("Child Component");
};
render() {
const { props } = this;
return <h1>count: {props.count}</h1>;
}
}
export default App;
结果
useRef
- 在函数组件中使用String Ref,Callback Ref , Create Ref 会抛出错误这个是因为函数组件中没有实例,所以函数组件中无法使用Create Ref
useRef的作用
- 获取DOM元素的节点
- 获取子组件的共享实例
- 渲染周期之间共享数据(state 不能寸尺跨渲染周期的数据,因为state的保存会触发组件的重新渲染)
获取DOM元素的节点
import React, { useEffect, useRef } from 'react';
function App() {
const h1Ref = useRef();
useEffect(() => {
console.log('useRef')
console.log(h1Ref.current)
}, [])
return <h1 ref={h1Ref}>Hello World!</h1>
}
export default App;
结果:
获取组件实例:
注: 因为函数组件没有实例,如果想用ref获取子组件的实例,子组件组要写成类组件。
import React, { Component, useEffect, useRef } from 'react';
function App() {
const childRef = useRef();
useEffect(() => {
console.log('useRef')
console.log(childRef.current)
childRef.current.handleLog();
}, [])
return (
<div>
<h1>Hello World!</h1>
<Child ref={childRef} count="1"/>
</div>
)
}
// 因为函数组件没有实例,如果想用ref获取子组件的实例,子组件组要写成类组件
class Child extends Component {
handleLog = () => {
console.log('Child Component');
}
render() {
const { count } = this.props;
return <h2>count: { count }</h2>
}
}
export default App;
结果:
渲染周期之间共享数据的存储
在类组件中,state 不嫩存储跨渲染周期的组件,因为state 的参数每一次保存都会触发组件的重渲染。
场景:声明一个参数为count = 0 ,组件初始化时count每秒钟加1,直到count > 5时停止增加,清除定时器。
把定时器设置成全局变量使用useRef挂载到current上
import React, { useState, useEffect, useRef } from "react";
function App() {
const [count, setCount] = useState(0);
// 把定时器设置成全局变量使用useRef挂载到current上
const timer = useRef();
// 首次加载useEffect方法执行一次设置定时器
useEffect(() => {
timer.current = setInterval(() => {
setCount(count => count + 1);
}, 1000);
}, []);
// count每次更新都会执行这个副作用,当count > 5时,清除定时器
useEffect(() => {
if (count > 5) {
clearInterval(timer.current);
}
});
return <h1>count: {count}</h1>;
}
export default App;