彻底掌握 useRef 的使用技巧
const refContainer = useRef(initialValue);
useRef
返回一个可变的 ref 对象,其 .current
属性被初始化为传入的参数( initialValue
)。返回的 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 属性中保存一个可变值的“盒子”。
然而, useRef()
比 ref
属性更有用。它可以很方便地保存任何可变值,其类似于在 class 中使用实例字段的方式。
只在更新时运行 effect
这是个比较罕见的使用场景。如果你需要的话,你可以 使用一个可变的 ref
手动存储一个布尔值来表示是首次渲染还是后续渲染,然后在你的 effect 中检查这个标识。
function Example () { const [count, setCount] = useState(0); const prevCountRef = useRef(false); useEffect(() => { if (prevCountRef.current) { console.log('只在更新时候执行') } else { prevCountRef.current = true } }); return ( <div> <div>{count}</div> <button onClick={() => {setCount(count+1)}}>+</button> </div> ) }
如果你发现自己经常在这么做,你可以为之创建一个自定义 Hook。
function Example () { const [count, setCount] = useState(0); const update = useUpdate() console.log(update, '是否更新') return ( <div> <div>{count}</div> <button onClick={() => {setCount(count+1)}}>+</button> </div> ) } function useUpdate () { const ref = useRef(false) useEffect(() => { ref.current = true }) return ref.current }
获取上一轮的 props 或 state
目前,你可以 通过 ref
来手动实现:
function Example () { const [count, setCount] = useState(0); const prevCountRef = useRef(0); useEffect(() => { prevCountRef.current = count }); const prevCount = prevCountRef.current console.log(prevCount, count, '之前的状态和现在的状态') return ( <div> <div>{count}</div> <button onClick={() => {setCount(count+1)}}>+</button> </div> ) }
这或许有一点错综复杂,但你可以把它抽取成一个自定义 Hook:
function Example () { const [count, setCount] = useState(0); const prevCount = usePrevious(count) console.log(prevCount, count, '之前的状态和现在的状态') return ( <div> <div>{count}</div> <button onClick={() => {setCount(count+1)}}>+</button> </div> ) } function usePrevious (value) { const ref = useRef() useEffect(() => { ref.current = value }) return ref.current }
函数中看到陈旧的 props 和 state
组件内部的任何函数,包括事件处理函数和 effect,都是从它被创建的那次渲染中被「看到」的。
function Example () { const [count, setCount] = useState(0); function handleAlertClick () { setTimeout(() => { console.log(count) }, 3000) } function increment () { let newCount = count + 1; setCount(newCount) } return ( <div> <div>{count}</div> <button onClick={increment}>+</button> <button onClick={handleAlertClick}>点击</button> </div> ) }
如果你刻意地想要从某些异步回调中读取 最新的 state,你可以用 一个 ref 来保存它,修改它,并从中读取。
function Example () { const [count, setCount] = useState(0); const ref = useRef(0) function handleAlertClick () { setTimeout(() => { console.log(ref.current) }, 3000) } function increment () { let newCount = count + 1; setCount(newCount) ref.current = newCount } return ( <div> <div>{count}</div> <button onClick={increment}>+</button> <button onClick={handleAlertClick}>点击</button> </div> ) }
请记住,当 ref 对象内容发生变化时, useRef
并不会通知你。变更 .current
属性不会引发组件重新渲染。如果想要在 React 绑定或解绑 DOM 节点的 ref 时运行某些代码,则需要使用回调 ref 来实现。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
下一篇: 不要相信一个熬夜的人说的每一句话
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论