React学习笔记(九) forwardRef和useImperativeHandle
forwardRef
ref 是为了获取某个节点的实例,但是函数式组件(PureComponent)是没有实例的,不存在 this 的,这种时候是拿不到函数式组件的 ref 的。为了解决这个问题,由此引入 React.forwardRef, React.forwardRef 允许某些组件接收 ref,并将其向下传递给子组件
基本使用如下
const Input = forwardRef((props, ref) => {
const inputRef = useRef(null)
return (
<div ref={inputRef}>hello</div>
)
})
export default function Index() {
const ipt = useRef(null)
const handleClick = useCallback(() => ipt.current.focus(), [ ipt ]);
return (
<div>
<Input ref={ipt}></Input>
</div>
)
}
useImperativeHandle
useImperativeHandle 和 React.forwardRef 必须是配合使用的。useImperativeHandle 可以让你在使用 ref 时自定义暴露给父组件的实例值
useImperativeHandle(ref, createHandle, [deps])
ref:定义 current 对象的 ref createHandle:一个函数,返回值是一个对象,即这个 ref 的 current
对象 [deps]:即依赖列表,当监听的依赖发生变化,useImperativeHandle 才会重新将子组件的实例属性输出到父组件
ref 的 current 属性上,如果为空数组,则不会重新输出。
一个关于 ref 转发的例子
import React, {
useState,
useRef,
useImperativeHandle,
useCallback
} from 'react';
import ReactDOM from 'react-dom';
const FancyInput = React.forwardRef((props, ref) => {
const [ fresh, setFresh ] = useState(false)
const attRef = useRef(0);
useImperativeHandle(ref, () => ({
attRef,
fresh
}), [ fresh ]);
const handleClick = useCallback(() => {
attRef.current++;
}, []);
return (
<div>
{attRef.current}
<button onClick={handleClick}>Fancy</button>
<button onClick={() => setFresh(!fresh)}>刷新</button>
</div>
)
});
const App = props => {
const fancyInputRef = useRef();
return (
<div>
<FancyInput ref={fancyInputRef} />
<button
onClick={() => console.log(fancyInputRef.current)}
>父组件访问子组件的实例属性</button>
</div>
)
}
ReactDOM.render(<App />, root);
通过 useImperativeHandle 将子组件的实例属性输出到父组件,而子组件内部通过 ref 更改 current 对象后,组件不会重新渲染,需要改变 useState 设置的状态才能更改。

浙公网安备 33010602011771号