文章目录
一、useRef
useRef
会在每次渲染时返回同一个 ref 对象
,这是因为它创建的是一个普通 Javascript 对象。
而 useRef() 和自建一个 {current: …} 对象的唯一区别是,useRef 会在每次渲染时返回同一个 ref 对象。
请记住,当 ref 对象内容发生变化时,useRef 并不会通知你。
变更 .current 属性不会引发组件重新渲染。如果想要在 React 绑定或解绑 DOM 节点的 ref 时运行某些代码,则需要使用回调 ref
来实现。
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onButtonClick = () => {
// `current` 指向已挂载到 DOM 上的文本输入元素
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}
本质上,useRef 就像是可以在其 .current 属性中保存一个可变值的“盒子”。
应用:获取上一轮的props和state
function PrevState() {
const [count, setCount] = React.useState(0);
const prevCountRef = React.useRef();
React.useEffect(() => {
prevCountRef.current = count;
});
const handleClick = () => {
setCount(count+1)
}
return (
<>
<button onClick={handleClick}>+1</button>
<h1>Now: {count}, before: {prevCountRef.current}</h1>
</>
)
}
二、useImperativeHandle
useImperativeHandle
可以让你在使用 ref 时自定义暴露给父组件的实例值
。在大多数情况下,应当避免使用 ref 这样的命令式代码。useImperativeHandle
应当与forwardRef
一起使用
function FancyInput(props, ref) {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
}
}));
return <input ref={inputRef} ... />;
}
FancyInput = forwardRef(FancyInput);
在本例中,渲染 FancyInput 的父组件只能调用它暴露出来的inputRef.current.focus(),其他不可调用,这样就规范了父组件可调用的权限。
参考链接: