forwardRef 实现引用传递
- useRef 创建的 ref 相当于函数组件的实例属性
- forwardRef 会把收到的 ref 转发给其子组件
// 子组件
const FancyButton = React.forwardRef((props, ref) => (
<div>
<input ref={ref} />
<button>
{props.children}
</button>
</div>
))
function App() {
const ref = React.createRef();
const handleClick = React.useCallback(
() => ref.current.focus(), []
)
return (
<div>
<FancyButton ref={ref}>Click me!</FancyButton>
<button onclick={handleClick}>获取焦点</button>
</div>
)
}
forwardRef 配合 useImperativeHandle
fancyInput 通过 useImperativeHandle hook 把组件属性以对象形式传递给父组件,父组件通过转发到子组件的 ref 来捕获需要的属性。
function FancyInput (props, ref) {
const [fresh, setFresh] = useState(0)
const attRef = useRef(0)
useImperativeHandle(ref, ()=> {
return {
attRef,
fresh
}
}, [fresh]);
// 只会在初始化调用一次
const handleClick = useCallback(()=> {
attRef.current = attRef.current + 1
}, [])
return (
<div>
{attRef.current}
<button onClick={handleClick}>Fancy</button>
<button onClick={()=>setFresh(!fresh)}>refresh</button>
</div>
)
}
FancyInput = forwardRef(FancyInput)
function App() {
const fancyInputRef = useRef();
return (
<div>
<FancyInput ref={fancyInputRef}>Click me!</FancyInput>
<hr />
<button onClick={() => console.log(fancyInputRef.current)}>
{/* 返回对象{attRef:{current: 0}, fresh: false} */}
父组件访问子组件的实例属性
</button>
</div>
)
}
第三个参数与 useEffect 类似,只有数组内的属性发生改变时,才会重新刷新返回给父组件对象。