提出:
与usestate不同在于用usesatate在每次状态更新的时候渲染,然而useRef不触发重新渲染(除非在控制台打印rerender这样手动渲染),但是二者相同在于组件重新渲染时候都会获取到之前的值。
使用场景一:
function MyAPP(){
let timer
const handleClick=()=>{
clearInterval(timer)//每次点击都清除之前的定时器(看上去 没问题)
timer=setInterval(()=>{},1000}(重新开启定时器)
}
}
在上面这段代码中,看似是清除之前定时器后再开启下一个,但是因为timer做为MyAPP函数的局部变量,再每次执行hanleClick这个回调函数时候都会重新开启很多个不同的timer。所以我们现在的需求是能通过记忆这个timer值(渲不渲染没事,只要记住),就需要useRef登场let timer=useRef(null)
使用场景二:
虽然react是MVVM,让我们的关注点放在数据逻辑上面,不用直接操作(亲自修改)DOM。有时候想直接修改dom。就需要useRef。
function MYAPP(){
const xxx=useRef(null)
const handelClick=()=>{
xxx.current+=1
}
return (
<div>
<h1 ref={xxx} onClick={handelClick}>Click me</h1>
</div>
)
}
如上例中我就可以通过xxx这个变量来获得dom。
回调形式:
function MYAPP(){
const xxx=useRef(null)
return (
<div>
<h1 ref={(xxxDOM)=>{xxxDOM.style.background='greenyellow'}}
onClick={handelClick}>Click me</h1>
</div>)}
通过回调函数的形式就不会在每次点击什么的触发,而是保存完这个js文件后,浏览器页面初次渲染这个DOM元素的时候为其添加背景颜色。
使用场景三:
和组件关联,获取组件中的东西。
const MyComponent(){
return MyComponent=forwardRef((props,ref)=>{
return (
<div>
<h2 ref={ref}>子组件</h2>
</div>
)
}
)
}
function MYAPP(){
const xxx=useRef(null)
return (
<div>
<h1 ref={(xxxDOM)=>{xxxDOM.style.background='greenyellow'}} onClick={handelClick}>Click me</h1>
<MyComponent ref={xxx}/>
</div>
)}
以上例中,通过在父组件myApp中定义useref,在调用子组件时候传递把ref=xxx传进去,用forwardRef包裹子组件后(允许子组件让父组件能访问到内部的元素),在子组件中传入两个形参,其中一个是ref,子组件里面指定Ref给h2。
使用场景四;
定制组建的ref,根据上面的方法看出子组件把所有内部元素暴露出去后没有封闭性,所以用useImperativeHnadle——定义当父组件用ref时候能访问到子组件的哪些。
const MyComponent(){
return MyComponent=forwardRef((props,ref)=>{
//配置组建的ref
useImperativeHandle(ref,()=>{
return {
function1()=>{console.log('子组件中的fun1ction1')},
function2()=>{console.log('子组件中的function2')},
}
})
return (
<div>
<h2 ref={ref}>子组件</h2>
</div>
)
}
)
}
function MYAPP(){
const xxx=useRef(null)
return (
<div>
<h1 ref={(xxxDOM)=>{xxxDOM.style.background='greenyellow'}} onClick={handelClick}>Click me</h1>
<MyComponent ref={xxx}/>
</div>
)
}
当控制台打印时候会获得一个object对象,里面包含function1,function2.这两个对象。提前定义好后就相当于子组件愿意给父组件什么,父组件就会获得什么。优点:既有封闭性,又有灵活性。