发布媒体回填的 revoke 移出 state updater
- VersionMediaApplyTarget 增加 getCover/getScreenshots,覆盖前先 revoke 旧的本地预览 - 两个调用点用 ref 提供当前媒体;updater 只做纯计算,StrictMode 重放不再撤销仍在用的 blob URL
This commit is contained in:
@@ -203,6 +203,8 @@ export function GamePublishPage({
|
||||
title: detail.game.title,
|
||||
});
|
||||
void applyVersionMediaDefaults(detail, {
|
||||
getCover: () => coverImageRef.current,
|
||||
getScreenshots: () => screenshotImagesRef.current,
|
||||
setCover: setCoverImage,
|
||||
setScreenshots: setScreenshotImages,
|
||||
isCancelled: () => cancelled,
|
||||
@@ -285,6 +287,8 @@ export function GamePublishPage({
|
||||
setPriceInput('');
|
||||
}
|
||||
void applyVersionMediaDefaults(detail, {
|
||||
getCover: () => coverImageRef.current,
|
||||
getScreenshots: () => screenshotImagesRef.current,
|
||||
setCover: setCoverImage,
|
||||
setScreenshots: setScreenshotImages,
|
||||
isCancelled: () => cancelled,
|
||||
|
||||
@@ -132,6 +132,8 @@ export function GameWorkMetadataEditor({
|
||||
.then((detail) => {
|
||||
if (cancelled) return;
|
||||
return applyVersionMediaDefaults(detail, {
|
||||
getCover: () => coverImageRef.current,
|
||||
getScreenshots: () => screenshotImagesRef.current,
|
||||
setCover: setCoverImage,
|
||||
setScreenshots: setScreenshotImages,
|
||||
isCancelled: () => cancelled,
|
||||
|
||||
@@ -44,6 +44,8 @@ describe('applyVersionMediaDefaults', () => {
|
||||
} as unknown as GameDistributionVersionDetail;
|
||||
|
||||
await applyVersionMediaDefaults(detail, {
|
||||
getCover: () => cover,
|
||||
getScreenshots: () => screenshots,
|
||||
setCover: (updater) => {
|
||||
cover = updater(cover);
|
||||
},
|
||||
|
||||
@@ -7,6 +7,13 @@ import {
|
||||
} from './gamePublishAssets';
|
||||
|
||||
type VersionMediaApplyTarget = {
|
||||
/**
|
||||
* 调用瞬间的当前封面。用 ref 读最新值而不是接收 updater:释放 blob URL 是副作用,放进
|
||||
* `setState` 的 updater 里会被 StrictMode 双调用/重放,撤销到仍被渲染引用的 URL。
|
||||
*/
|
||||
getCover: () => GamePublishImage | null;
|
||||
/** 调用瞬间的当前截图,理由同 {@link getCover}。 */
|
||||
getScreenshots: () => GamePublishImage[];
|
||||
setCover: (
|
||||
updater: (current: GamePublishImage | null) => GamePublishImage | null,
|
||||
) => void;
|
||||
@@ -48,19 +55,20 @@ export async function applyVersionMediaDefaults(
|
||||
.filter(Boolean);
|
||||
if (apply.isCancelled()) return;
|
||||
// 覆盖前先释放被替换掉的本地预览 blob URL:这一步之后旧对象不再有人引用,不 revoke 就泄漏。
|
||||
apply.setCover((current) => {
|
||||
revokeGamePublishImagePreview(current);
|
||||
return coverObjectKey ? buildCover('') : null;
|
||||
});
|
||||
apply.setScreenshots((current) => {
|
||||
for (const image of current) revokeGamePublishImagePreview(image);
|
||||
return screenshotObjectKeys.map((objectKey, index) => ({
|
||||
// revoke 在 dispatch 之前做,updater 只负责纯计算,重放不会撤销到仍在用的 URL。
|
||||
revokeGamePublishImagePreview(apply.getCover());
|
||||
for (const image of apply.getScreenshots()) {
|
||||
revokeGamePublishImagePreview(image);
|
||||
}
|
||||
apply.setCover(() => (coverObjectKey ? buildCover('') : null));
|
||||
apply.setScreenshots(() =>
|
||||
screenshotObjectKeys.map((objectKey, index) => ({
|
||||
id: createGamePublishImageId(),
|
||||
objectKey,
|
||||
src: '',
|
||||
name: `截图 ${index + 1}`,
|
||||
}));
|
||||
});
|
||||
})),
|
||||
);
|
||||
|
||||
const coverPreview = await resolveGamePublishImagePreview(
|
||||
coverObjectKey,
|
||||
|
||||
Reference in New Issue
Block a user