如何使用 React Hooks 根据组件的当前状态更新组件的状态?
How can I update a component's state based on its current state with React Hooks?
在我的组件中,我是 运行 一个函数,它迭代状态中的键并在异步函数完成时更新属性。但是,看起来它正在将状态更新为函数 运行.
之前存在的状态
这是我的组件的代码:
interface VideoDownloaderProps {
videos: string[];
}
const VideoDownloader: React.FC<VideoDownloaderProps> = ({ videos }) => {
const [progress, setProgress] = useState({} as { [key: string]: string });
const [isDownloading, setIsDownloading] = useState(false);
async function initialSetup(vids: string[]) {
const existingKeys = await keys();
setProgress(
vids.reduce<{ [key: string]: string }>((a, b) => {
a[b] = existingKeys.indexOf(b) > -1 ? "downloaded" : "queued";
return a;
}, {})
);
}
useEffect(() => {
initialSetup(videos);
}, [videos]);
async function download() {
setIsDownloading(true);
const existingKeys = await keys();
for (const videoUrl of videos) {
if (existingKeys.indexOf(videoUrl) === -1) {
setProgress({ ...progress, [videoUrl]: "downloading" });
const response = await fetch(videoUrl);
const videoBlob = await response.blob();
await set(videoUrl, videoBlob);
}
setProgress({ ...progress, [videoUrl]: "downloaded" });
}
setIsDownloading(false);
}
return (
<div>
<button disabled={isDownloading} onClick={download}>
Download Videos
</button>
{Object.keys(progress).map(url => (
<p key={url}>{`${url} - ${progress[url]}`}</p>
))}
</div>
);
};
本质上,这会遍历 URL 的列表,下载它们,然后将状态中的 URL 设置为 "downloaded"
。但是,我看到的行为是 URL 从 "queued"
转移到 "downloading"
,然后在下一个 URL 开始下载后又回到 "queued"
。
我认为罪魁祸首是这一行:
setProgress({ ...progress, [videoUrl]: "downloaded" });
我认为 progress
始终处于与 download
执行时相同的状态。
在使用 Hooks 之前,我可以将更新程序函数传递给 setState
,但我不确定如何在 useState
挂钩中重用现有状态。
您可以像 setState
一样传递更新程序函数。所以,在这段代码中,你会 运行:
setProgress(progress => ({ ...progress, [videoUrl]: "downloading" }));
这将传递 progress
的当前值,允许您根据其当前值更新状态。
在我的组件中,我是 运行 一个函数,它迭代状态中的键并在异步函数完成时更新属性。但是,看起来它正在将状态更新为函数 运行.
之前存在的状态这是我的组件的代码:
interface VideoDownloaderProps {
videos: string[];
}
const VideoDownloader: React.FC<VideoDownloaderProps> = ({ videos }) => {
const [progress, setProgress] = useState({} as { [key: string]: string });
const [isDownloading, setIsDownloading] = useState(false);
async function initialSetup(vids: string[]) {
const existingKeys = await keys();
setProgress(
vids.reduce<{ [key: string]: string }>((a, b) => {
a[b] = existingKeys.indexOf(b) > -1 ? "downloaded" : "queued";
return a;
}, {})
);
}
useEffect(() => {
initialSetup(videos);
}, [videos]);
async function download() {
setIsDownloading(true);
const existingKeys = await keys();
for (const videoUrl of videos) {
if (existingKeys.indexOf(videoUrl) === -1) {
setProgress({ ...progress, [videoUrl]: "downloading" });
const response = await fetch(videoUrl);
const videoBlob = await response.blob();
await set(videoUrl, videoBlob);
}
setProgress({ ...progress, [videoUrl]: "downloaded" });
}
setIsDownloading(false);
}
return (
<div>
<button disabled={isDownloading} onClick={download}>
Download Videos
</button>
{Object.keys(progress).map(url => (
<p key={url}>{`${url} - ${progress[url]}`}</p>
))}
</div>
);
};
本质上,这会遍历 URL 的列表,下载它们,然后将状态中的 URL 设置为 "downloaded"
。但是,我看到的行为是 URL 从 "queued"
转移到 "downloading"
,然后在下一个 URL 开始下载后又回到 "queued"
。
我认为罪魁祸首是这一行:
setProgress({ ...progress, [videoUrl]: "downloaded" });
我认为 progress
始终处于与 download
执行时相同的状态。
在使用 Hooks 之前,我可以将更新程序函数传递给 setState
,但我不确定如何在 useState
挂钩中重用现有状态。
您可以像 setState
一样传递更新程序函数。所以,在这段代码中,你会 运行:
setProgress(progress => ({ ...progress, [videoUrl]: "downloading" }));
这将传递 progress
的当前值,允许您根据其当前值更新状态。