useRef
是经常使用的 API,但还有一个 createRef
的 API,你知道他们的区别吗?经过 React.useRef and React.createRef: The Difference 这篇文章,你能够了解到什么时候该使用它们。html
其实原文就阐述了这样一个事实:useRef
仅能用在 FunctionComponent,createRef
仅能用在 ClassComponent。前端
第一句话是显然的,由于 Hooks 不能用在 ClassComponent。react
第二句话的缘由是,createRef
并无 Hooks 的效果,其值会随着 FunctionComponent 重复执行而不断被初始化:git
function App() {
// 错误用法,永远也拿不到 ref
const valueRef = React.createRef();
return <div ref={valueRef} />;
}
复制代码
上述 valueRef
会随着 App 函数的 Render 而重复初始化,这也是 Hooks 的独特之处,虽然用在普通函数中,但在 React 引擎中会获得超出普通函数的表现,好比初始化仅执行一次,或者引用不变。github
为何 createRef
能够在 ClassComponent 正常运行呢?这是由于 ClassComponent 分离了生命周期,使例如 componentDidMount
等初始化时机仅执行一次。微信
原文完。闭包
那么知道如何正确建立 Ref 后,还知道如何正确更新 Ref 吗?ide
因为 Ref 是贯穿 FunctionComponent 全部渲染周期的实例,理论上在任何地方均可以作修改,好比:函数
function App() {
const valueRef = React.useRef();
valueRef.current += 1;
return <div />;
}
复制代码
但其实上面的修改方式是不规范的,React 官方文档里要求咱们避免在 Render 函数中直接修改 Ref,请先看下面的 FunctionComponent 生命周期图:spa
从图中能够发现,在 Render phase
阶段是不容许作 “side effects” 的,也就是写反作用代码,这是由于这个阶段可能会被 React 引擎随时取消或重作。
修改 Ref 属于反作用操做,所以不适合在这个阶段进行。咱们能够看到,在 Commit phase
阶段能够作这件事,或者在回调函数中作(脱离了 React 生命周期)。
固然有一种状况是能够的,即 懒初始化:
function Image(props) {
const ref = useRef(null);
// ✅ IntersectionObserver is created lazily once
function getObserver() {
if (ref.current === null) {
ref.current = new IntersectionObserver(onIntersect);
}
return ref.current;
}
// When you need it, call getObserver()
// ...
}
复制代码
懒初始化的状况下,反作用最多执行一次,并且仅用于初始化赋值,因此这种行为是被容许的。
为何对反作用限制的如此严格?由于 FunctionComponent 增长了内置调度系统,为了优先响应用户操做,可能会暂定某个 React 组件的渲染,具体能够看第 99 篇精读:精读《Scheduling in React》
Ref 不只能够拿到组件引用、建立一个 Mutable 反作用对象,还能够配合 useEffect
存储一个较老的值,最经常使用来拿到 previousProps
,React 官方利用 Ref 封装了一个简单的 Hooks 拿到上一次的值:
function usePrevious(value) {
const ref = useRef();
useEffect(() => {
ref.current = value;
});
return ref.current;
}
复制代码
因为 useEffect
在 Render 完毕后才执行,所以 ref
的值在当前 Render 中永远是上一次 Render 时候的,咱们能够利用它拿到上一次 Props:
function App(props) {
const preProps = usePrevious(props);
}
复制代码
要实现这个功能,仍是要归功于 ref
能够将值 “在各个不一样的 Render 闭包中传递的特性”。最后,不要滥用 Ref,Mutable 引用越多,对 React 来讲可维护性通常会越差。
你还挖掘了 useRef
哪些有意思的使用方式?欢迎在评论区留言。
讨论地址是:精读《useRef 与 createRef 的区别》 · Issue #236 · dt-fe/weekly
若是你想参与讨论,请 点击这里,每周都有新的主题,周末或周一发布。前端精读 - 帮你筛选靠谱的内容。
关注 前端精读微信公众号
版权声明:自由转载-非商用-非衍生-保持署名(创意共享 3.0 许可证)