我有一个进度条,单击它即可从 60 开始进度,一直到 100。我可以使用 settinterval 并设置相应的状态来实现此目的。
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>
);
}
我使用 ref 将进度动态增加 10,当进度达到 100 时,我将其清除并将消息显示为
Upload Complete
。代码运行得很好。
沙箱:https://codesandbox.io/s/simple-react-progress-bar-forked-yfz9xb?file=/src/useProgress.jsx:0-436
现在我希望
initiate
内部的内容将其移动到自定义挂钩,该挂钩应该处理 setinterval 功能并设置对象,以便功能保持不变。可能这个 cutsom 钩子应该以初始百分比作为数字,并且可能是状态设置器。
知道如何编写这个自定义钩子。这就是我的尝试
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);
};
当您在函数组件中运行某些内容并希望将其变成钩子时,这通常比人们想象的要容易。通常,您可以将功能代码直接复制到钩子中;使钩子接受代码外部所需的任何内容作为参数;并从钩子中返回调用组件所需的任何内容作为返回值(如果有多个值,请将它们包装在数组[元组]或对象中)。
在您的情况下,只需将组件中
return
之前的所有内容复制到挂钩中,然后让挂钩返回 file
和 initiate
:
export const useProgress = () => {
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 [file, initiate];
};
然后
App
这样使用它:
export default function App() {
const [file, initiate] = useProgress();
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>
);
}
您可以提供
updater
处理函数和 timer
起始值作为参数,这些参数可以根据您使用自定义挂钩的位置而变化。
这也可以:
import { useRef } from "react";
const useProgress = (updater, timer) => {
const mockRef = useRef(timer);
const initiate = () => {
const intervalID = setInterval(() => {
if (mockRef.current >= 100) {
clearInterval(intervalID);
updater((prevState) => ({
...prevState,
status: 100
}));
} else {
mockRef.current = mockRef.current + 10;
updater((prevState) => ({
...prevState,
status: mockRef.current
}));
}
}, 200);
};
return initiate;
};
export default useProgress;
在你的
App.jsx
...
...
export default function App() {
const [file, setFile] = useState({ status: 0, error: "" });
const initiate = useProgress(setFile, 60);
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>
);
}
...
Codesandbox 演示:
如果状态是一个数组,那么
fileIndex
可以传递到自定义钩子中: