React 集成
在 React 里,wasm runtime 最好放在应用级别,而不是组件级别。推荐形态是 provider,或者一个稳定的模块级单例,只加载一次并在整棵组件树之间共享。
推荐结构
- 在类似
VgmstreamRuntimeProvider 的 provider 里创建 runtime。
- 通过 context 或自定义 hook 暴露解码能力。
- 让播放 UI 组件只关心渲染和用户交互,不负责 runtime 生命周期。
Provider 草图
const runtime = createVgmstreamRuntimeManager({
loadModule: createBrowserModuleLoader({
scriptUrl: '/assets/vgmstream_wasm_min.js',
wasmUrl: '/assets/vgmstream_wasm_min.wasm',
}),
});
const VgmstreamRuntimeContext = createContext(runtime);
export function VgmstreamRuntimeProvider({ children }) {
return (
<VgmstreamRuntimeContext.Provider value={runtime}>
{children}
</VgmstreamRuntimeContext.Provider>
);
}
为什么这样更稳
wasm 资源体积不小,若把初始化散落到组件内部,很容易反复触发重复下载、重复实例化和难以解释的性能波动。单一 runtime 能让冷启动和热路径的指标更清晰,也更容易做缓存命中分析。
常见反模式
- 不要在组件函数体里创建 runtime。
- 不要在按钮点击回调里创建 runtime。
- 不要在切歌时重新抓取 wasm 资源。
- 不要把 runtime 绑定到寿命很短的列表项组件上。
清理建议
切换曲目后,要在 effect cleanup 或拥有当前解码结果的控制器层统一回收旧 blob URL。
React Integration
In React, the wasm runtime should live at app scope. The recommended shape is a provider or a stable module-level singleton that loads once and is shared by the rest of the tree.
Recommended structure
- Create the runtime in a provider such as
VgmstreamRuntimeProvider.
- Expose decode helpers through context or a custom hook.
- Keep playback UI components focused on rendering and user events.
Provider sketch
const runtime = createVgmstreamRuntimeManager({
loadModule: createBrowserModuleLoader({
scriptUrl: '/assets/vgmstream_wasm_min.js',
wasmUrl: '/assets/vgmstream_wasm_min.wasm',
}),
});
const VgmstreamRuntimeContext = createContext(runtime);
export function VgmstreamRuntimeProvider({ children }) {
return (
<VgmstreamRuntimeContext.Provider value={runtime}>
{children}
</VgmstreamRuntimeContext.Provider>
);
}
Why this matters
The wasm bundle is large enough that per-component initialization is wasteful. A single runtime means one fetch path, one initialization path, and consistent cache-hit behavior across route changes and repeated playback actions.
Avoid these anti-patterns
- Do not create the runtime inside a component body.
- Do not create the runtime inside a button click callback.
- Do not refetch the wasm file every time the selected track changes.
- Do not tie runtime lifetime to short-lived list item components.
Cleanup
When a track changes, revoke the old blob URL in effect cleanup or in the player controller that owns the current decoded result.