I am having a progress bar which on click starts its progress from 60 to all the way upto 10 for each of the file of files array. I am a using the ref to dynamically increment the progress by 10 and when its 100, I clear it and bring the message as Upload Complete. Code works just fine.
I have moved the mechanism of initiating progress onto a custom hook, that basically takes setter, the interval and a file name for which it has to update upload progress.
I am initializing the hook inside the parent, but each of the file name I will only get when I click each of the file names button. how can I pass the name of the file?
Sandbox: https://codesandbox.io/s/progress-bar-r0zcjn?file=/src/App.js
Component:
import React, { useState, useRef } from "react";
import "./styles.css";
import ProgressBar from "./ProgressBar";
import useProgress from "./useProgress";
const appStyles = {
height: 20,
width: 500,
margin: 50
};
export default function App() {
const [files, setFiles] = useState([
{ name: "file1", status: 0 },
{ name: "file2", status: 0 },
{ name: "file3", status: 0 }
]);
const initiateProgress = useProgress(setFiles, 60);
const initiate = (name) => {
console.log(name);
};
return (
<div className="App" style={appStyles}>
{files.map((file) => {
return (
<div key={file.name}>
<button type="button" onClick={() => initiate(file.name)}>
{file.name}
</button>
<ProgressBar bgColor={"#DF8100"} progress={file.status} />
{file.status === 100 && <span>Upload complete</span>}
</div>
);
})}
</div>
);
}
Hook
import { useRef } from "react";
const useProgress = (updater, timer, name) => {
const mockRef = useRef(timer);
const handleProgress = () => {
const intervalID = setInterval(() => {
if (mockRef.current >= 100) {
clearInterval(intervalID);
updater((prevState) =>
prevState.map((item, itemIndex) =>
item.name === name ? { ...item, status: 100 } : item
)
);
} else {
mockRef.current = mockRef.current + 10;
updater((prevState) =>
prevState.map((item, itemIndex) =>
item.name === name ? { ...item, status: mockRef.current } : item
)
);
}
}, 200);
};
return handleProgress;
};
export default useProgress;
You need to define another component combining the useProgress
hook logic and ProgressBar
component. Try like this:
const FileProgress = ({ file, updater }) => {
const initiateProgress = useProgress(updater, 60, file.name);
return (
<div key={file.name}>
<button type="button" onClick={initiateProgress}>
{file.name}
</button>
<ProgressBar bgColor={"#DF8100"} progress={file.status} />
{file.status === 100 && <span>Upload complete</span>}
</div>
);
};
export default function App() {
const [files, setFiles] = useState([
{ name: "file1", status: 0 },
{ name: "file2", status: 0 },
{ name: "file3", status: 0 }
]);
return (
<div className="App" style={appStyles}>
{files.map((file) => {
return <FileProgress file={file} updater={setFiles} />;
})}
</div>
);
}
Code sandbox demo: