useRef函数
使用useRef可以直接操作一个改变值后不需要渲染的值。
1. 使用useRef
useRef返回的是一个对象而不是数组:
jsx
import { useRef } from 'react'
function App() {
const num = useRef(0)
const clickHandler = () => {
// 对普通变量也提供记忆功能,不会一直从0开始
num.current = num.current + 1
console.log(num.current)
}
return (
<div>
hello App
<div>
<button onClick={clickHandler}>点击添加</button>
</div>
<div>
{num.current}
</div>
</div>
)
}
export default App
运行结果,会发现num的值已经到4,但是jsx片段并没有重新渲染:
2. 使用useRef场景
jsx
import { useRef, useState } from 'react'
function App() {
const num = useRef(0)
const [stateVariable, setStateVariable] = useState(0)
// 如果不适用useRef, 各自的作用域将会清理不了timer
let timer = null
const clickHandler = () => {
setStateVariable(stateVariable + 1)
clearInterval(timer)
timer = setInterval(() => {
num.current = num.current + 1
console.log(num.current)
}, 1000)
}
return (
<div>
hello App
<div>
<button onClick={clickHandler}>点击添加</button>
</div>
<div>
{num.current}, {stateVariable}
</div>
</div>
)
}
export default App
运行效果:
3. useRef和useState的区别
ref | state |
---|---|
useRef(initValue)返回 | useState(initValue)返回state变量的当前值和一个state设置函数([value, setValue]) |
更改时不会触发重新渲染 | 更改时触发重新渲染。 |
可变--你可以在渲染过程之外修改和更新current的值 | "不可变"--你必须使用state设置函数来修改state变量,从而排队重新渲染。 |
你不应该在渲染期间读取或写入current值。 | 你可以随时读取state设置。但是每次渲染都有自己不变的state快照。 |
4. 使用ref操作DOM
由于React会自动处理更新DOM以匹配你的渲染输出,因此你在组件中通常不需要操作DOM。但是有时你可能需要访问由React管理的DOM元素。例如让一个节点获得焦点、滚动到它或测量它的尺寸和位置。
jsx
import { useRef, useState } from 'react'
function App() {
const [num, setNum] = useState(0)
const myRef = useRef(null)
const clickHandler = () => {
setNum(num+1)
myRef.current.style.backgroundColor = 'red'
}
return (
<div>
hello App
<div>
<button onClick={clickHandler}>点击添加</button>
</div>
// 固定写法:ref={xxx}
<div ref={myRef}>
{num}
</div>
</div>
)
}
export default App
运行结果: 如果需要在jsx片段中使用ref:
jsx
import { useState } from 'react'
function App() {
const [dataList, setDataList] = useState([
{id:1, name:'test'},
{id:2, name:'jack'},
{id:3, name:'zhangshan'},
])
return (
<div>
hello App
<ul>
{dataList.map((item) => (
<li key={item.id} ref={(myRef)=>{myRef.style.backgroundColor='blue'}}>{item.name}</li>
))}
</ul>
</div>
)
}
export default App
运行效果:
4. 使用forwardRef转发
当组件添加ref属性的时候,需要forwardRef进行转发,forwardRef让您的组件通过ref向父组件公开DOM节点。
jsx
import { useRef, forwardRef } from 'react'
const MyInput = forwardRef(function MyInput(props, ref) {
return (
<input type="text" ref={ref} />
)
})
function App() {
const myRef = useRef(null)
const handleClick = ()=>{
myRef.current.focus()
myRef.current.style.background = 'red'
}
return (
<div>
<div>
<button onClick={handleClick}>点击</button>
</div>
<MyInput ref={myRef} />
</div>
)
}
export default App
运行效果: 可以看到ref转发到子组件MyInput里面的input组件上面,input组件就可以暴露到父组件上面,被外面进行操作。