Bootstrap

UseRef的正确使用与滥用避雷

正常情况下,我们在react hooks中用到最多的就是变量的某种状态的定义以及更改

我们使用input来展示示例

 const [name, setName] = useState('aa')

    return (
        <>
            <input value={name} onChange={e => setName(e.target.value)}></input>
            <div>My name is {name}</div>           
        </>
    )

在这里插入图片描述

这是一个基本的react hooks应用程序,为了开始谈论什么是ref,而不是了解实施的细节,我们想在屏幕上呈现组件渲染的次数,应该怎么做呢?

一、存储渲染次数或者存储不因渲染而重新声明改变的值

我们可以加个div来展示组件渲染的次数,大多数人都想去再定义一些状态变量称为渲染计数,并设置渲染计数

const [renderCount, setRenderCount]  = useState(0)

useEffect(() => {
	setRenderCount(prevRenderCount => prevRenderCount + 1)
})

<div>I rendered {renderCount} times</div>

但这样有一个巨大的危险就是,当我们更新状态时,导致组件重新渲染,所以我的组件第一次渲染,声明并改变了状态,然后又触发渲染,又重新声明改变状态,这会导致我的组件状态进入无限循环,在无限循环中建立自己……

在这里插入图片描述
在这里插入图片描述

所以我们这个场景呢就使用ref来解决,因为useRef的值变化是不受渲染所影响的不会重新更新

使用ref我们设置它的默认值为1(因为最少会渲染一次)

const renderCount = useRef(0)

它只返回一个对象,它的结构看起来像这样

renderCount  = {current: 0}

renderCount只是具有当前current属性的对象,当我们更新当前对象时,不同的或者多次的渲染都会保留这个属性,因此在这里我们可以使用它来进行渲染计数

useEffect(() => {
	renderCount.current = renderCount.current + 1
})
  <div>I rendered {renderCount.current} times</div>

现在我们更改name触发渲染,renderCount的值就会增加

在这里插入图片描述
在这里插入图片描述
现在我们可以看到,ref值与我们组件的值 是完全分开的~所以我们也可以在其中存储先前的(如上一次渲染的)值 ,并且在这次渲染中用到~

  const prevName = useRef('')
 useEffect(() => {
        // setRenderCount(prevRenderCount => prevRenderCount + 1)
        // renderCount.current = renderCount.current + 1
        prevName.current = name
    })

  <div>My name is {name} and it used to be {prevName.current}</div>    

在这里插入图片描述

在这里插入图片描述

二、像文档选择器一样使用

这个应该是我们最常见的ref用法了

  const input = useRef(null)
  
  const divText = useRef(null)
  divText.current = 'woman'

  <input ref={input} value={name}></input>
  <div>{divText.current}</div>
    
  <button onClick={() => {
       console.log(input)
       console.log(input.current)
       console.log(input.current.value)
  }}>change name</button>

这就相当于我们的文档选择器 - getElementById的用法了

在这里插入图片描述

那么有些人可能就非得用ref值 的current去改变这个值 (没错这个人是我~)

 <button onClick={() => {
                console.log(input)
                console.log(input.current)
                console.log(input.current.value)

                 input.current.focus()

                input.current.value = 'jerry'
                console.log('更新后的inputvalue', input.current.value)
                divText.current = 'man'
                console.log('更新后的divText', divText.current)
                
            }}>change name</button>

但是我们发现,普通的div是只有值变化了,但是视图没有变化(没有引发渲染所以视图没有变化)

在这里插入图片描述
在这里插入图片描述

但是改变input元素呢,值不会发生改变 ,但视图可以变化(虽然没有引起渲染但视图也发生变化了),我们只是手动设置了此输入ref的值,这结果是我们不希望看到的,所以建议还是用useState改变状态输入哈~

在这里插入图片描述
在这里插入图片描述

;