如何编写自定义React Hook实现进度条从60到100的递增
正确实现进度条逻辑的自定义Hook
我现有一个点击后从60%开始递增至100%的进度条,已通过setInterval和状态管理实现功能,代码如下:
import React, { useState, useRef } from "react"; import ProgressBar from "./ProgressBar"; export default function App() { const [file, setFile] = useState({ status: 0, error: "" }); const mockRef = useRef(60); const initiate = () => { const intervalID = setInterval(() => { if (mockRef.current >= 100) { clearInterval(intervalID); setFile((prevState) => ({ ...prevState, status: 100 })); } else { setFile((prevState) => ({ ...prevState, status: mockRef.current })); mockRef.current = mockRef.current + 10; } }, 200); }; return ( <div className="App" style={appStyles}> <button type="button" onClick={initiate}> Click Me! </button> <ProgressBar bgColor={"#DF8100"} progress={file.status} /> {file.status === 100 && <span>Upload complete</span>} </div> ); }
当前代码运行正常,点击按钮后进度条从60%逐步递增至100%,完成后显示“Upload complete”提示。现在希望将initiate函数内的逻辑迁移至自定义Hook中,该Hook需处理setInterval逻辑并维护状态,保持原有功能不变,可接收初始百分比和状态设置器作为参数。我的尝试代码如下:
import { useRef } from "react"; export const useProgress = (state, timer) => { const mockRef = useRef(timer); const intervalID = setInterval(() => { if (mockRef.current >= 100) { clearInterval(intervalID); return { ...state, status: 100 }; } else { mockRef.current = mockRef.current + 10; return { ...state, status: mockRef.current }; } }, 200); };
请问如何正确编写这个自定义Hook?
正确的自定义Hook实现
你的尝试存在两个核心问题:一是Hook初始化时就直接执行setInterval,不符合“点击按钮才触发”的需求;二是通过返回对象无法更新组件状态,应该直接调用传入的状态设置器。以下是修正后的代码:
import { useRef } from "react"; export const useProgress = (initialProgress, setState) => { // 保存定时器ID,避免重复触发 const intervalRef = useRef(null); // 维护当前进度的引用 const progressRef = useRef(initialProgress); const initiateProgress = () => { // 若已有定时器运行,先清除 if (intervalRef.current) { clearInterval(intervalRef.current); } // 重置进度到初始值 progressRef.current = initialProgress; intervalRef.current = setInterval(() => { if (progressRef.current >= 100) { clearInterval(intervalRef.current); intervalRef.current = null; setState(prev => ({ ...prev, status: 100 })); } else { setState(prev => ({ ...prev, status: progressRef.current })); progressRef.current += 10; } }, 200); }; // 返回触发进度更新的函数 return initiateProgress; };
在App组件中使用该Hook
修改原App组件,引入并使用自定义Hook:
import React, { useState } from "react"; import ProgressBar from "./ProgressBar"; import { useProgress } from "./useProgress"; export default function App() { const [file, setFile] = useState({ status: 0, error: "" }); // 传入初始进度60和状态设置器setFile,获取触发函数 const initiate = useProgress(60, setFile); return ( <div className="App" style={appStyles}> <button type="button" onClick={initiate}> Click Me! </button> <ProgressBar bgColor={"#DF8100"} progress={file.status} /> {file.status === 100 && <span>Upload complete</span>} </div> ); }
关键说明
- 定时器控制:新增
intervalRef保存定时器ID,避免重复点击创建多个定时器,进度完成后清空引用。 - 状态更新:直接调用传入的
setState(即原组件的setFile)更新状态,确保组件响应进度变化。 - 进度维护:
progressRef跟踪当前进度,保持和原逻辑一致的递增节奏。 - 触发时机:将定时器创建逻辑封装在
initiateProgress函数中,返回给组件由点击事件触发,符合原需求。
内容的提问来源于stack exchange,提问作者lrr59
相关产品推荐
相关产品推荐

