useref
要想使用好ref,得知道ref是什么?ref用来获取组件实例,也就是真实DOM,在class组件中是有实例的,但是函数组件没有实例怎么获取?我们可以使用useref这个hook.
基本使用
import { useRef } from 'react';
function MyComponent() {
const intervalRef = useRef(0);
const inputRef = useRef(null);
//...
以上是使用useref创建一个ref
import { useRef } from 'react';
export default function Counter() {
let ref = useRef(0);
function handleClick() {
ref.current = ref.current + 1;
alert('You clicked ' + ref.current + ' times!');
}
return (
<button onClick={handleClick}>
Click me!
</button>
);
}
在这个例子中,创建一个ref并且初始值设置为0;handleClick函数中对ref的值+1;这样做的结果就是当你的组件刷新的时候,ref的值不会被重置为0,这意味着,你可以使用 ref.current 属性来存储和访问在组件多次渲染之间需要保持不变的值。
关于ref转发
将子组件的值转发给父组件,父组件可以调用子组件实例,在react中,使用forwardRef创建支持转发的组件. forwardRef接受一个函数作为参数,该函数返回一个新的函数式组件.
import React, { useRef, forwardRef } from 'react';
const ChildComponent = forwardRef((props, ref) => {
return (
<div ref={ref}>
This is the child component.
</div>
);
});
const ParentComponent = () => {
const childRef = useRef(null);
const handleButtonClick = () => {
childRef.current.style.backgroundColor = 'red';
}
return (
<div>
<button onClick={handleButtonClick}>Change Child Background Color</button>
<ChildComponent ref={childRef} />
</div>
);
};
export default ParentComponent;
在这个例子中在父组件中生成childref,然后ChildComponent中将childref传递ref属性,在ChildComponent组件中forwardRef接受ref,这时候父组件就可以获取子组件实例.而在父组件中,通常不需要写 forwardRef 函数,只需要创建一个 ref 对象,并将其传递给子组件的 ref 属性即可实现 ref 转发。
useImperativeHandle
这个钩子,当你想在父组件中使用子组件实例,但是又不想全部暴露,而是只可以使用子组件中特定的一些函数.
useImperativeHandle 接受两个参数:第一个参数是一个 ref 对象,用于引用子组件实例,第二个参数是一个回调函数,该函数返回一个对象,该对象包含要暴露给父组件的函数。
import React, { forwardRef, useRef, useImperativeHandle } from 'react';
const FancyInput = forwardRef((props, ref) => {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
},
clear: () => {
inputRef.current.value = '';
},
}));
return <input type="text" ref={inputRef} />;
});
export default function App() {
const fancyInputRef = useRef();
function handleClick() {
fancyInputRef.current.focus();
}
function handleClear() {
fancyInputRef.current.clear();
}
return (
<div>
<FancyInput ref={fancyInputRef} />
<button onClick={handleClick}>Focus input</button>
<button onClick={handleClear}>Clear input</button>
</div>
);
}
可以看到首先APP组件将fancyInputRef转发给FancyInput组件,
FancyInput组件使用forwardRef来接收ref,
并且在组件里生成inputRef,useImperativeHandle使用这个钩子将父组件传过来的ref和子组件内部的方法连接起来.
就可以在父组件使用focus和clear方法.