React新文档:不要滥用Ref哦~
共 5881字,需浏览 12分钟
·
2022-06-28 23:18
作者:卡颂
简介:《React技术揭秘》作者
来源:SegmentFault 思否社区
大家好,我卡颂。
React新文档有个很有意思的细节:useRef、useEffect这两个API的介绍,在文档中所在的章节叫Escape Hatches(逃生舱)。
显然,正常航行时是不需要逃生舱的,只有在遇到危险时会用到。
如果开发者过多依赖这两个API,可能是误用。
在React新文档:不要滥用effect哦中我们谈到useEffect的正确使用场景。
今天,我们来聊聊Ref的使用场景。
为什么是逃生舱?
先思考一个问题:为什么ref、effect被归类到逃生舱中?
这是因为二者操作的都是脱离React控制的因素。
effect中处理的是副作用。比如:在useEffect中修改了document.title。
document.title不属于React中的状态,React无法感知他的变化,所以被归类到effect中。
同样,使DOM聚焦需要调用element.focus(),直接执行DOM API也是不受React控制的。
虽然他们是脱离React控制的因素,但为了保证应用的健壮,React也要尽可能防止他们失控。
失控的Ref
对于Ref,什么叫失控呢?
首先来看不失控的情况:
执行ref.current的focus、blur等方法
执行ref.current.scrollIntoView使element滚动到视野内
执行ref.current.getBoundingClientRect测量DOM尺寸
执行ref.current.remove移除DOM
执行ref.current.appendChild插入子节点
export default function Counter() { const [show, setShow] = useState(true); const ref = useRef(null); return ( <div>
<button
onClick={() => {
setShow(!show);
}}>
Toggle with setState </button>
<button
onClick={() => {
ref.current.remove();
}}>
Remove from the DOM </button>
{show && <p ref={ref}>Hello world</p>} </div>
);
}
如何限制失控
高阶组件
低阶组件
function MyInput(props) { return <input {...props} />;
}
function MyInput(props) { const ref = useRef(null); return <input ref={ref} {...props} />;
}
function Form() { return ( <>
<MyInput/>
</>
)
}
function MyInput(props) { return <input {...props} />;
}function Form() { const inputRef = useRef(null); function handleClick() {
inputRef.current.focus();
} return ( <>
<MyInput ref={inputRef} />
<button onClick={handleClick}>
input聚焦 </button>
</>
);
}点击后,会报错:
人为取消限制
const MyInput = forwardRef((props, ref) => { return <input {...props} ref={ref} />;
});function Form() { const inputRef = useRef(null); function handleClick() {
inputRef.current.focus();
} return ( <>
<MyInput ref={inputRef} />
<button onClick={handleClick}>
Focus the input </button>
</>
);
}
useImperativeHandle
const MyInput = forwardRef((props, ref) => { const realInputRef = useRef(null); useImperativeHandle(ref, () => ({ focus() {
realInputRef.current.focus();
},
})); return <input {...props} ref={realInputRef} />;
});
{ focus() {
realInputRef.current.focus();
},
}