useRef
- 类组件、React 元素用 React.createRef,函数组件使用 useRef
- useRef 返回一个可变的 ref 对象,其
current属性被初始化为传入的参数(initialValue) - useRef 返回的 ref 对象在组件的整个生命周期内保持不变,也就是说每次重新渲染函数组件时,返回的ref 对象都是同一个(使用 React.createRef ,每次重新渲染组件都会重新创建 ref)
const refContainer = useRef(initialValue);
使用方法
import React,{useRef} from 'react';
const Demo = ()=>{
return <div></div>
}
const Father=()=>{
const inputRef = useRef<any>()
const Child = React.forwardRef(Demo);
const getFocus=()=> {
inputRef.current.focus();
}
return (
<div>
<input type="text" ref={inputRef} />
<button onClick={getFocus}>获得焦点</button>
</div>
)
}
export default Father
forwardRef
因为函数组件没有实例,所以函数组件无法像类组件一样可以接收 ref 属性,因此需要使用forwardRef包裹一层, 子组件接受 props 和 ref 作为参数
function Child(props,ref){
return (
<input type="text" ref={ref}/>
)
}
Child = React.forwardRef(Child);
function Parent(){
const inputRef = useRef();
function getFocus(){
inputRef.current.focus();
}
return (
<>
<Child ref={inputRef}/>
<button onClick={getFocus}>获得焦点</button>
</>
)
}
useImperativeHandle
-
useImperativeHandle可以让你在使用 ref 时,自定义暴露给父组件的实例值,不能让父组件想干嘛就干嘛 -
在大多数情况下,应当避免使用 ref 这样的命令式代码。useImperativeHandle 应当与 forwardRef 一起使用
-
父组件可以使用操作子组件中的多个 ref
function Child(props,parentRef){
// 子组件内部自己创建 ref
let focusRef = useRef();
let inputRef = useRef();
useImperativeHandle(parentRef,()=>(
// 这个函数会返回一个对象
// 该对象会作为父组件 current 属性的值
// 通过这种方式,父组件可以使用操作子组件中的多个 ref
return {
focusRef,
inputRef,
name:'计数器',
focus(){
focusRef.current.focus();
},
changeText(text){
inputRef.current.value = text;
}
}
});
return (
<>
<input ref={focusRef}/>
<input ref={inputRef}/>
</>
)
}
Child = forwardRef(Child);
function Parent(){
const parentRef = useRef();//{current:''}
function getFocus(){
parentRef.current.focus();
// 因为子组件中没有定义这个属性,实现了保护,所以这里的代码无效
parentRef.current.addNumber(666);
parentRef.current.changeText('<script>alert(1)</script>');
console.log(parentRef.current.name);
}
return (
<>
<ForwardChild ref={parentRef}/>
<button onClick={getFocus}>获得焦点</button>
</>
)
}
useRef补充
useRef 的作用
- 获取React JSX中的DOM元素,获取后你就可以控制DOM的任何东西了
- 用useRef来保存变量,注意:useRef 每次都会返回相同的引用,ref不会受到闭包影响,使用useRef来保存的变量永远都是最新的值,它值的改变不会引起Render。
React Hooks 中存在 Capture Value 的特性
function MessageDemo() {
const [message, setMessage] = useState("");
const showMessage = () => {
alert("You said: " + message);
};
const handleSendClick = () => {
setTimeout(showMessage, 3000);
};
const handleMessageChange = e => {
setMessage(e.target.value);
};
return (
<>
<input value={message} onChange={handleMessageChange} />
<button onClick={handleSendClick}>Send</button>
</>
);
}
handleSendClick函数3秒后打印的showMessage是这个函数在执行时的message值,在打印前的这3秒内你再修改message打印也不会更新,而在类组件中不会出现这种情况,只有函数组件有,使用useRef可以跳过Capture Value。
useRef保存变量的用法
- 保存定时器