为什么这两个一起写,是因为这两个关联性很大,逐一介绍。
1、作用:用于在函数组件中创建一个持久化的引用变量。这个引用变量可以在组件的多次渲染之间保持不变,并且可以访问和修改 DOM 元素或其他组件实例的实例变量。
2、示例
import React, { useState, useRef } from 'react';
function TextInput() {
const [value, setValue] = useState('');
const inputRef = useRef(null);
function focusInput() {
inputRef.current.focus();
}
return (
setValue(e.target.value)}
ref={inputRef}
/>
);
}
function App() {
return ;
}
在这个示例中,我们首先使用 useState
Hook 创建了一个名为 value
的状态变量,它保存了输入框中的值。然后,我们使用 useRef
Hook 创建了一个名为 inputRef
的引用变量,并将其初始化为 null
。
在输入框标签中,我们使用了 ref={inputRef}
属性将 inputRef
和输入框绑定起来。这样,我们就可以在组件中的其他地方访问和修改输入框元素的属性。
在 focusInput
函数中,我们使用了 inputRef.current
来获取输入框元素,并调用了 focus()
方法来聚焦输入框。
最后,在 TextInput
组件中,我们渲染了一个输入框和一个按钮。当用户点击按钮时,它会调用 focusInput
函数,将焦点聚焦到输入框上。
这是 useRef
的基本用法。通过使用 useRef
,你可以在函数组件中创建一个持久化的引用变量,并访问和修改 DOM 元素或其他组件实例的实例变量。
(示例2)
import React, { useEffect, useRef } from 'react';
function Timer() {
const timerRef = useRef(null);
useEffect(() => {
// 在组件挂载时启动定时器
timerRef.current = setInterval(() => {
console.log('Timer tick');
}, 1000);
// 在组件卸载时清除定时器
return () => {
clearInterval(timerRef.current);
};
}, []);
return (
Timer
);
}
function App() {
return ;
}
在这个示例中,我们使用 useRef
创建了一个名为 timerRef
的引用变量,并将其初始化为 null
。
在 useEffect
钩子中,我们使用 timerRef.current
来获取当前的定时器引用。当组件挂载时,我们通过 setInterval
创建一个定时器,并将其赋值给 timerRef.current
。定时器每隔一秒钟输出 "Timer tick"。
同时,我们还在 useEffect
中返回一个清理函数,它会在组件卸载时执行。在清理函数中,我们使用 clearInterval
来清除定时器,以防止内存泄漏。
最后,在 Timer
组件中,我们渲染了一个标题标签。但重点是,我们在组件的生命周期方法中使用了 useEffect
和 useRef
来启动和清除定时器。
这是另一个 useRef
的例子,展示了它如何用于在函数组件中引用和管理副作用.
3、总结:
通过上面两个示例,可以了解到,useref有两个作用:
1、保存 DOM 元素的引用:获取组件的属性等操作
2、缓存组件状态:简单的理解为,和usestate不同的是,useRef
返回的 ref
对象可以在组件的每次渲染过程中保持不变,即使组件重新渲染,它也不会被重新赋值。
1、作用:用于在函数组件中自定义向父组件暴露的实例值和方法。通常情况下,React 推荐使用 props 来进行组件之间的通信,但有时候我们可能需要在函数组件中使用类似于 Class 组件中的实例方法和属性。
2、用法:useImperativeHandle
接受两个参数:ref
和一个回调函数。回调函数会接收一个参数,即父组件传递给子组件的 ref
对象。在回调函数中,我们可以定义这个 ref
对象所暴露出来的实例值和方法。
3、示例
import React, { useRef, useImperativeHandle, forwardRef } from 'react';
const ChildComponent = forwardRef((props, ref) => {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
},
getValue: () => {
return inputRef.current.value;
}
}));
return ;
});
function ParentComponent() {
const childRef = useRef();
function handleClick() {
childRef.current.focus();
const value = childRef.current.getValue();
console.log('Input value:', value);
}
return (
);
}
上面的示例中,我们创建了一个 ChildComponent
组件,并使用 useRef
声明了一个 childRef
引用。然后,在 useImperativeHandle
的回调函数中,我们定义了要向父组件暴露的两个实例方法:focus
和 getValue
。在 focus
方法中,我们通过 childRef.current
来访问子组件的 DOM 元素,并使其获取焦点。在 getValue
方法中,我们同样通过 childRef.current
来获取子组件输入框的值。
在父组件中,我们使用 React.forwardRef
包裹了 ChildComponent
,以便能够接收父组件传递的 ref
。然后,我们创建了一个 childRef
引用,将其传递给 ForwardedChildComponent
。当点击按钮时,我们调用 childRef.current
上的 focus
方法和 getValue
方法,并输出输入框的值。
总结:子组件想暴露给父组件什么完全由子组件决定。和vue中的ref不同。