一、useRef和createRef
1. 作用于普通DOM
![在这里插入图片描述](https://img-blog.csdnimg.cn/457dc3bf6929455a94cf1320b8533cd5.png#pic_center)
import { Input, Button } from 'antd';
import { useRef, createRef } from 'react';
import type { InputRef } from 'antd';
const RefDemo = () => {
const inputEL = useRef<InputRef>(null);
const inputEL2 = useRef<HTMLInputElement>(null);
const inputEL3 = createRef<HTMLInputElement>();
const getInput = () => {
console.log('antd DOM', inputEL.current?.input?.value);
console.log('原生 DOM', inputEL2.current?.value);
console.log('createRef', inputEL3.current?.value);
};
return (
<div>
<p>antd Input:<Input ref={inputEL} style={{width: 167}} /></p>
<p>原生 Input:<input type="text" ref={inputEL2} /></p>
<p>createRef Input:<input type="text" ref={inputEL3} /></p>
<p><Button onClick={getInput}>获取Input Value</Button></p>
</div>
);
};
export default RefDemo;
2. 作用于子组件,需要用到两个方法 useImperativeHandle 和 forwardRef
- forwardRef:包裹要添加ref的子组件,有两个参数,组件的props和组件的ref
- useImperativeHandle:两个参数,组件的 ref 和一个回调函数,返回值是子组件的方法或者变量,提供给父组件调用
- 注意!在父组件中使用 ref 去更新子组件,只是子组件更新,父组件不会同步更新,需要手动更新
![在这里插入图片描述](https://img-blog.csdnimg.cn/77e567c72567414991a0ecc84741b081.png#pic_center)
import { Button } from 'antd';
import { useRef, useImperativeHandle, forwardRef, useState } from 'react';
const Child = forwardRef((props, ref) => {
const [count, setCount] = useState<number>(0);
useImperativeHandle(ref, () => ({
count: count,
changeCount() {
setCount(count + 1);
}
}));
return (
<div>
<p>子组件count: { count }</p>
</div>
);
});
type ChildRefType = {
count: number,
changeCount: () => void;
}
const RefDemo = () => {
const childRef = useRef<ChildRefType>();
const [reload, setReload] = useState<boolean>(false);
const changeChild = () => {
childRef.current?.changeCount();
};
return (
<div>
<p>
父组件:count:{childRef.current?.count}
<Button onClick={changeChild}>调用子组件的方法</Button>
<Button onClick={() => setReload(!reload)}>手动更新父组件</Button>
</p>
<Child ref={childRef} />
</div>
);
};
export default RefDemo;
- 注意!此方法不适用于createRef,原因如下,每次父组件渲染都会重新创建ref,所获取的值都为undefined
二、useRef和createRef区别
- createRef会在组件每次渲染的时候重新创建
- useRef只会在组件首次渲染时创建
![在这里插入图片描述](https://img-blog.csdnimg.cn/051c53dfbb8a4f199747317726fa8b73.png#pic_center)
import { useState, useRef, createRef } from 'react';
import { Button } from 'antd';
const RefDemo = () => {
const [count, setCount] = useState<number>(0);
const inputEL = useRef<HTMLInputElement>(null);
const inputEL2 = createRef<HTMLInputElement>();
const showCount = () => {
console.log('useRef Input:', inputEL.current?.value);
console.log('createRef Input:', inputEL2.current?.value);
};
const updateComponent = () => {
setCount(count + 1);
};
console.log(inputEL.current?.value, inputEL2.current?.value, `组件${count === 0 ? '初' : count}次渲染`);
return(
<div>
<p>useRef Input:<input type="text" ref={inputEL} /></p>
<p>createRef Input:<input type="text" ref={inputEL2} /></p>
<p><Button onClick={updateComponent}>重新渲染</Button></p>
<p><Button onClick={showCount}>show value</Button></p>
</div>
);
};
export default RefDemo;