首先说一下为什么要使用useRef和createRef:
useRef和createRef可以存放任何东西,最常见的用法就是操作DOM(如在input上放ref,可直接操作input),还有就是当作定义的一个跨越渲染不受渲染影响的变量。
操作DOM好理解就是可以不使用原声js来操作DOM了, 更方便了
export default () => {
const inputRef = useRef()
return (
<div>
<input type="text" ref={inputRef} />
<button onClick={() => {inputRef.current.onFocus()}}>聚焦</button>
<div>input的值{inputRef.current.getValue()}</div>
</div>
)
}
定义跨渲染的变量:
export default () => {
const [value, setValue] = useState(1)
return (
<div>
<p>value的值:{value}</p>
<button onClick={() => {setValue(value+1)}}>按我+1哦</button>
<button onClick={() => {
setTimeout(() => {
alert(value)
}, 3000)
}}>点我弹窗</button>
</div>
)
}
上图中代码当你点击弹窗按钮,然后立马在点击“+1按钮”, 结果会怎样呢?
页面上的value值会显示2,3s后会弹窗显示值1
为什么会发生这样的情况呢?
因为每次使用react使用setState的时候都会触发渲染函数,把把函数组建重新执行一下, 那有人会问问什么重新执行,state没有保持原来的数据而是使用了最新的数据,个人认为可以理解成, 函数组建每次的渲染都会保留一份属于自己的数据,会通过state会通过setState把最新的state传给组件,然后组件渲染DOM, 每一次渲染都属保留自己的那一份state值。
如何理解保留本次渲染的state值呢?
如上图代码先点击弹窗按钮,执行到setTimeout异步函数, 需要使用的value值是本次渲染的1,点击完弹窗按钮,立刻点击+1按钮, 此时弹窗还没出现,而setState已经出发value值+1,并重新渲染,所以页面上显示的value值是2,而弹窗里显示的值虽然是后出现的, 但是它使用的依然是上一次渲染的value值1.
useRef和createRef的区别:
useRef在函数组建中使用, createRef在类组建中使用,createRef在函数组建中使用会失去它的意义, 它会随着组建重新执行而被重新赋值,createRef 每次渲染都会返回一个新的引用,而 useRef 每次都会返回相同的引用
export default () => {
const [val, setVal] = useState(1)
const uRef = useRef()
const cRef = React.createRef()
if (!uRef.current) {
uRef.current = val
}
if (!cRef.current) {
cRef.current = val
}
return (
<div>
<p onClick={() => {setVal(val+1)}}>+1</p>
<p>val: {val}</p>
<p>uRef: {uRef.current}</p>
<p>cRef: {cRef.current}</p>
</div>
)
}
如上图结果所示,每次函数组建被执行,createRef也被初始化了