byUgochukwu Prosper

我需要警告你:如果初学者知道元素可以通过useRef轻松访问,vanilla Javascript 将成为当天的订单,这会玷污我们在 React 中预先学习的状态管理知识。尽管看起来很棘手,但它就是那么强大。UseRef仅应在需要时用于在我们的组件中创建引用。我们将在本文中深入探讨;您将学习useRefReact 钩子的一些日常使用,我们还将使用它构建一个秒表计时器应用程序。

[本文目标](https://res.cloudinary.com/practicaldev/image/fetch/s--L0hCbUDo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://blog .openreplay.com/181535655953f279527473caf6af12c1/image01.gif)

开发区

你需要安装 React 18 和 Node 才能完成。如果要安装 React 18,请按照以下步骤操作:

npm install react@18 react-dom@18

进入全屏模式 退出全屏模式

要利用 React 18 的所有新功能,您需要转到您的入口文件,通常是index.js,并将所有内容替换为:

import React from 'react';
import { createRoot } from 'react-dom/client';
import './index.css';
import App from './App';

const root = createRoot(document.getElementById("root"));
root.render(<App/>);

进入全屏模式 退出全屏模式

为什么要使用Ref,如何使用?

React 状态有一些限制,这就是 React 引用派上用场的地方。useRef返回一个可变 ref 对象,其.current属性初始化为传递的参数 (initialValue)。返回的对象将在组件的整个生命周期内持续存在。

useRef相对于 useState 的一个优势可以很好地表述为“引用不会触发重新渲染,但在状态下,当状态更新时它会触发重新渲染。

需要注意的是,我们可以访问组件中的任何内容并将焦点设置为元素。正如正手所说,我将继续说明如何做到这一点,但在此之前,我想指出useRef钩子的两个基本关键:

  • 值保持不变。

  • 更新参考不会在重新渲染时跳闸。

这些密钥到底需要什么?我将举一个我想做的例子,展示一个组件在屏幕上渲染的次数。一个快速的解决方法是使用 useState 钩子,但它会给我们留下一个无限循环;我来给你展示。

import React, { useState, useEffect } from 'react';
function Render() {

  const [render, setrender]=useState();
  useEffect(()=>{
    setrender(prevrender=>prevrender+1)
  })
  console.log(render);

  return (
    <>
      <div>
        This component rendered= {render} times
      </div>
    </>

  )
};

进入全屏模式 退出全屏模式

那里的代码将导致您进入无限循环,因为状态不是此类事情的最佳选择。如果状态不是,那是什么?一个快速的解决方法是使用 Refs。

Ref 与 state 类似,因为它在组件的渲染之间持续存在,但如前所述,它不会在发生更改时导致组件重新更新。让我们继续使用useRef修复上述逻辑。

    const render = useRef(0);
    // current {0}

进入全屏模式 退出全屏模式

上面是useRef的语法。它默认返回一个对象,它是当前属性,默认情况下它也将自身设置为 0。每当当前属性更新时,它都会在我们的各种渲染之间持续存在。

import React, { useRef, useEffect, useState } from 'react';
function Render() {
  const [age, setAge] = useState(20);
  const render = useRef(0)

  useEffect(() => {
    render.current = render.current + 1
  })
  function updateAge() {
    setAge(prevage => prevage + 1)
  }

  return (
    <>
      <div className='center'>
        <p>This site is strictly for adults ranging from 20-...</p>
        <p>you are {age} years old</p>
        <button onClick={updateAge}>set age</button>
        <p>This state rendered {render.current} times</p>
      </div>

    </>

  )
};

export default Render;

进入全屏模式 退出全屏模式

[React中的问题](https://res.cloudinary.com/practicaldev/image/fetch/s--bQy8C6AL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://blog. openreplay.com/3ed278b0ed919fdf31c77b793824ad30/image02.gif)

上面的代码是一个简单的注册逻辑。与使用 use state hook 来指示组件被渲染的次数不同,使用useRef不会让我们陷入无限循环,如果我们将updateAge更改为增加 5 或其他值,它永远不会导致我们的组件重新渲染.

    function updateAge() {
    setAge(prevage => prevage + 5)
    }

进入全屏模式 退出全屏模式

[增加 5](https://res.cloudinary.com/practicaldev/image/fetch/s--VYG5iLO8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://blog.openreplay .com/8c58221d09b094d63d4eb9ece75a3b33/image03.gif)

让我们继续创建一个带有一些样式的输入并设置一个参考。这些是我们将遵循的步骤来设置焦点;

  1. 我们需要一个输入字段来将焦点返回给它。

  2. 我们需要定义引用。

  3. 我们需要一个按钮来将焦点返回到我们组件中的输入元素。

  4. 我们需要为我们的元素添加引用属性。

import React, { useState, useRef } from 'react';

import './App.css';

function App() {
  const [insert, setInsert] = useState('');
  //const render = useRef()

  const handleOnchange = (e) => {
    setInsert(e.target.value);
  }

  return (
    <div className="App">
      <input
        type="text"
        placeholder='use reference'
        value={insert}
        onChange={handleOnchange}
        className="input"
      />
      <br /><br />

      <div> <p className='text'>{insert}</p></div>
    </div>
  );
}

export default App;

进入全屏模式 退出全屏模式

一些款式:

.input {
      border-radius: 10px;
      padding: 10px;
      margin: 20%;
  }

  .body {
      background-color: burlywood;
      display: flex;
      justify-content: center;
      align-items: center;
  }

  .text {
      color: white;
      margin: 0;
  }

进入全屏模式 退出全屏模式

我们现在可以继续为它设置一个参考。首先,通过导入useRef钩子并定义我们的引用,我们可以将引用命名为reference

import React, { useState, useRef } from 'react';<-//FOCUS HERE

import './App.css';

function App() {
  const [insert, setInsert] = useState('');
  const reference = useRef() <-//FOCUS HERE

进入全屏模式 退出全屏模式

 Then, we need to create the function that enables us to set focus on the input;

进入全屏模式 退出全屏模式

const returnCursor = () => { 
  reference.current.focus()
}

进入全屏模式 退出全屏模式

我们还需要将上面的代码传递给我们的 JSX。我们如何做到这一点?我们需要创建一个按钮并将函数传递给它,所以每当我们单击该按钮时,它都会运行函数return cursor。让我们这样做。

<div className='button'>
  <input
          type="button"
          value="Return cursor"
          onClick={returnCursor}
        />
      </div>

//a little styling
.button {
        border-radius: 10%;
        padding: 10%;
        color: black;
    }

进入全屏模式 退出全屏模式

最后,我们需要在输入元素中设置属性;

ref={reference}

进入全屏模式 退出全屏模式

我们刚刚强调了一段时间的聚焦,但是,我们究竟在聚焦什么?每当单击按钮时,它意味着触发输入元素,并且当触发元素时,文本光标重新出现。

[用useRef移动光标](https://res.cloudinary.com/practicaldev/image/fetch/s--4M8ks6ZK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://blog .openreplay.com/8df784eb3d56b7921f68635c234b183b/image04.gif)

上面的视频说明了我们已经能够用useRef做什么。

开源会话重播

OpenReplay是一个开源的会话重播套件,可让您查看用户在您的 Web 应用程序上的操作,帮助您更快地解决问题。 OpenReplay 是自托管的,可以完全控制您的数据。

[replayer.png](https://res.cloudinary.com/practicaldev/image/fetch/s--cO1f9e_o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://static.openreplay .com/images/banner-blog.png)

开始享受您的调试体验 -开始免费使用 OpenReplay.

UseRef 构建秒表计时器

在教程的开头,我们看到了一个视频;让我们在学习useRef的基础知识的同时构建它,它可以让每个人都可以使用这个钩子脱颖而出。

import React, { useState, useRef } from 'react';

import './App.css';


function App() {
  const [insert, setInsert] = useState('');
  const [secs, setSecs] = useState(0);
  const reference = useRef(0);
  const time = useRef();

  const handleOnchange = (e) => {
    setInsert(e.target.value);
    reference.current++;
  }

  const startTime = () => {
    time.current = setInterval(() => {
      reference.current++;
      setSecs(prev => prev + 1)
    }, 1000)
  }

  const stopTime = () => {
    clearInterval(time.current);
    time.current = 0;
  }

  const resetTime = () => {
    stopTime();
    if (secs) {
      reference.current++;
      setSecs(0);
    }
  }
  return (
    <div className='App'>
      <input
        type="text"
        placeholder='use reference'
        value={insert}
        onChange={handleOnchange}
        className="input"
      />
      <br /><br />
      <div className='text'> <p className='text'>Please input your name: {insert}</p></div>
      <div >
      </div>
      <input type="button" value="start time" onClick={startTime} />
      <input type="button" value="stop time" onClick={stopTime} />
      <input type="button" value="reset time" onClick={resetTime} />
      <p>Timer{secs}</p>
      <div>
        <p>Render:[{reference.current}]</p>
      </div>
    </div>
  );
}

export default App;

进入全屏模式 退出全屏模式

造型:

.input {
    padding: 10px;
    border-radius: 20px;
    width: 70em;
}

.button {
    padding: 20px;
    border-radius: 10px;
    display: flex;
    justify-content: center;
    align-items: center;
}

.body {
    display: flex;
    justify-content: center;
    align-items: center;
}

.text {
    margin: 10px;
}

进入全屏模式 退出全屏模式

上面有一个停止定时器和输入。它每秒渲染一次并显示渲染和计时器,即使我们输入。每当应用程序重新渲染时,我们不会因为使用useRef挂钩而丢失值。

[最终结果](https://res.cloudinary.com/practicaldev/image/fetch/s--xYMXNIlX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://blog.openreplay .com/181535655953f279527473caf6af12c1/image05.gif)

结论

使用UseState挂钩定期更新 React 组件的状态可能会产生意想不到的结果。

总的来说,带回家的是:

  • 我们可以将值存储在 refs 中并更新它们,这比useState更有效,当值在一秒钟内多次更新时,这可能会很昂贵。

  • 返回的对象将在组件的整个生命周期内持续存在。

  • 需要注意的是,我们可以访问组件中的任何内容并将焦点设置到元素。

时事通讯

Logo

React社区为您提供最前沿的新闻资讯和知识内容

更多推荐