使用 useRef 构建 React Timer 应用程序
byUgochukwu Prosper 我需要警告你:如果初学者知道元素可以通过useRef轻松访问,vanilla Javascript 将成为当天的订单,这会玷污我们在 React 中预先学习的状态管理知识。尽管看起来很棘手,但它就是那么强大。UseRef仅应在需要时用于在我们的组件中创建引用。我们将在本文中深入探讨;您将学习useRefReact 钩子的一些日常使用,我们还将使用它构建一个秒
byUgochukwu Prosper
我需要警告你:如果初学者知道元素可以通过useRef
轻松访问,vanilla Javascript 将成为当天的订单,这会玷污我们在 React 中预先学习的状态管理知识。尽管看起来很棘手,但它就是那么强大。UseRef
仅应在需要时用于在我们的组件中创建引用。我们将在本文中深入探讨;您将学习useRef
React 钩子的一些日常使用,我们还将使用它构建一个秒表计时器应用程序。
[](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;
进入全屏模式 退出全屏模式
[中的问题](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)
}
进入全屏模式 退出全屏模式
[](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)
让我们继续创建一个带有一些样式的输入并设置一个参考。这些是我们将遵循的步骤来设置焦点;
-
我们需要一个输入字段来将焦点返回给它。
-
我们需要定义引用。
-
我们需要一个按钮来将焦点返回到我们组件中的输入元素。
-
我们需要为我们的元素添加引用属性。
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}
进入全屏模式 退出全屏模式
我们刚刚强调了一段时间的聚焦,但是,我们究竟在聚焦什么?每当单击按钮时,它意味着触发输入元素,并且当触发元素时,文本光标重新出现。
[移动光标](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 是自托管的,可以完全控制您的数据。
[](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
更有效,当值在一秒钟内多次更新时,这可能会很昂贵。 -
返回的对象将在组件的整个生命周期内持续存在。
-
需要注意的是,我们可以访问组件中的任何内容并将焦点设置到元素。
更多推荐
所有评论(0)