Svelte中改用IndexedDB存储电影数据后响应式失效,需手动刷新才更新列表
问题根源定位
两个核心逻辑偏差导致列表不自动更新,和MovieList组件本身的实现完全无关:
- 响应式触发链路天生断裂:模板里的
{#await}块绑定的是组件初次挂载时生成的一次性Promise,这个Promise一旦完成状态变更(成功/失败),后续不管IndexedDB里的数据怎么变化,这个块都不会再重新执行渲染,必须刷新页面重新初始化组件才能重新走一遍加载逻辑。 - 写入操作后没有任何数据同步动作:
submitMovie函数执行完db.movies.put之后,既没有等待写入完成的逻辑,也没有重新拉取全量列表、同步到响应式变量的步骤,组件永远拿不到新增后的最新数据。
另外你之前写的db.movies.count(function (value) { ... })这段本身就有API使用错误:Dexie的所有数据库操作都是返回Promise,根本不支持传入回调函数的写法,你写的这个回调永远不会被执行,之前能加载出数据属于链路巧合。
调整方向
- 把原来绑定给
{#await}的一次性Promise,替换成普通响应式变量存储电影列表,单独用一个变量记录加载状态:- 在
onMount生命周期函数里,等组件挂载完成后拉取全量电影数据,赋值给响应式变量 - 封装一个通用的列表刷新函数,方便后续写操作完成后调用
- 在
- 补全写入操作的异步逻辑:
db.movies.put是异步操作,等写入完成后调用封装好的刷新函数,重新拉取最新的列表数据赋值给响应式变量,Svelte检测到变量值变化就会自动更新传入MovieList的props,不需要手动刷新页面。 - (可选优化)接入Dexie自带的表变更监听,只要movies表发生新增、修改、删除操作,就自动触发列表刷新,哪怕是跨标签页的数据变更也能同步更新,省得每次写操作都手动调用刷新函数。
修正后的核心代码参考
<script> import { onMount } from 'svelte'; import MovieInput from "./MovieInput.svelte"; import MovieList from "./MovieList.svelte"; import Search from "./Search.svelte"; import db from "./db.js"; // 响应式存储列表和加载状态 let movies = []; let isLoading = true; // 通用列表刷新逻辑 const refreshMovieList = async () => { movies = await db.movies.toArray(); isLoading = false; } onMount(async () => { // 初始化加载数据 await refreshMovieList(); // 可选:绑定表变更监听,自动同步数据变化 db.movies.hook('creating', refreshMovieList); db.movies.hook('updating', refreshMovieList); db.movies.hook('deleting', refreshMovieList); }) // 提交新电影 const submitMovie = async (movie) => { await db.movies.put({ title: movie.title, rating: movie.rating }); // 写入完成后触发刷新(如果绑定了hook监听这步可省略) await refreshMovieList(); }; </script> <div class="main"> <h1>Movie Journal</h1> <MovieInput on:submitMovie={(event) => submitMovie(event.detail.movie)} /> {#if isLoading} <div>Loading movies...</div> {:else} <MovieList {movies} /> {/if} </div>
MovieList.svelte的代码完全不需要修改,它本身只是接收props渲染列表,不存在逻辑问题。
内容的提问来源于stack exchange,提问作者Mattias
相关产品推荐
相关产品推荐

