useRef钩子函数

92 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第30天,点击查看活动详情

React 中有两个创建 ref 的方法,createRef() 和 useRef()。使用 ref,只需要将创建的 ref 赋到 DOM 和类组件的 ref 属性上即可。当组件挂载之后,ref 的 current 属性访问的就是对该节点的引用,DOM 元素时就是该元素,类组件时就是该组件的实例。

createRef

this.inputRef = createRef()

<input ref={this.inputRef}>

由于ref 的 current 属性访问的就是对该节点的引用,DOM 元素时就是该元素 ,所以打印this.inputRef.current可以得到input这个真实dom。

ref也可以用在父子组件中用来传值:

子组件为Child组件

父组件app中引用:

this.ChildRef = createRef()
< Child ref={this.ChildRef}/>

通过在app中就可以使用this.ChildRef.current打印出Child这个子组件了,如果Child中有value/state这些可以一并打印出来

useRef--针对函数组件的基础使用

原生dom,非受控

function App(){
const [value,setValue] = useState("zhangsan")
const inputRef = useRef() //{current=null}
const handleSubmit = ()=>{
  //获取input数据
  const name = inputRef.current.value
  console.log(name)
  //可以打印到zhangsan
  setValue(name)
}
    return(
    <div>
     <input type="text" ref={this.inputRef} value={value}/> 
     <button onClick={ handleSubmit } >提交</button>
     </div>
   )
}

对比:受控方式

  <input type="text" ref={this.inputRef} value={value} onChange=(e)=>{setValue(e.target.value)}/> 

未解决问题

捕获值问题:

场景,在输入框中输入信息后,点击提交,然后立即在5s内在输入,观察打印的是第一次输入的值还是连带着最后一次输入的值。

先定义好input中的value数据

const [value,setValue] = useState('')

然后来显示value

<input type="text" value={value} />

在input上放onChange点击事件,实时获取到输入的数据

handleChange=(e)=>{
  setValue(e.target.value)
}

现在可以实时同步value数据了,那点击按钮将在5s之后弹出我输入的数据

const handleSubmit = () =>{
  setTimeout(()=>{
    alert(value) //弹出value
  },5000)
}

输入aaa,点击按钮在5s之后弹窗,在此之际未到5s之后再次输入sss。请问是输出aaa还是aaasss呢?

//源代码
 function App1(){
         const [value,setValue] = useState('')
         const handleChange=(e)=>{
            setValue(e.target.value)
        }
        const handleClick=()=>{
            setTimeout(() => {
                alert(value)
            }, 5000);
        }
         return(
            <div>
              <input type="text" value={value} onChange={handleChange} />    
              <button onClick={handleClick}>按钮</button>
            </div>
         )
        }

结果打印aaa

image.png

原因是,在函数组件中使用useState时,创建的变量是类似存在于闭包机制,打印的并不是实时同步的value,变量的地址是前后不一致的,所以打印的是之前输入的数据。

那接下来要做的就是解决闭包机制,让input这个真实dom中的value等于实时输入的value

用到useRef啦!

在input组件中使用ref来获取真实dom

const lastValue = useRef()
return(
 <input type="text" ref={lastValue} />
)

这样就可以获取lastValue.current值为input真实dom了。

下面就要将真实dom上的value弹窗出来。

setTimeout(()=>{
  const value = lastValue.current.value
  alert(value)
},5000)

会打印出来的,我确信。

//源代码
  function App(){
        const lastValue = useRef()
        const handleClick=()=>{
            setTimeout(() => {
                const value = lastValue.current.value
                alert(value)
            }, 5000);
        }
         return(
            <div>
              <input type="text"  ref={lastValue}  />    
              <button onClick={handleClick}>按钮</button>
            </div>
         )
        }

image.png

直接打印真实dom上的value就好啦,无需通过useState存放value值再打印。

说了这么多函数组件,那来看看类组件中是什么样呢?

类组件

同样是输入框和按钮

<input type="text" value={value} onChange={handleChange} />
<button onClick={handleSubmit}>按钮</button>

设置createRef()

const lastValue = createRef()

将lastValue中的current对象设置为输入的数据,然后打印lastValue中的current

const handleChange = (e) =>{
    setValue(e.target.value)
    lastValue.current = e.target.value
}
const handleSubmit = ()=>{
 setTimeout(()=>{
  alert(lastValue.current)
 },5000)
}

return(
 <input type="text" value={value} onChange={handleChange} />
 <button onClick={handleSubmit}>按钮</button>
)

直接运行查看结果 image.png

类组件中不存在闭包机制的问题,可以直接打印出在5s中输入的内容。