苗条的反应性

Posted

技术标签:

【中文标题】苗条的反应性【英文标题】:Svelte Reactivity 【发布时间】:2021-05-26 13:18:33 【问题描述】:

尝试将使用 localStorage 的简单教程转换为使用 IndexedDB,但反应性有问题。在我刷新页面之前,电影列表不会更新。谁能指出我正确的方向?谢谢!

以下代码已更新,其中一个答案是 Thomas Heennes 建议的一些更改,谢谢!仍然有需要手动页面刷新的问题。还添加了 MovieList.svelte

App.svelte

<script>
    import MovieInput from "./MovieInput.svelte";
    import MovieList from "./MovieList.svelte";
    import Search from "./Search.svelte";
    import db from "./db.js";
    import Dexie from "dexie";

    //get a promise containing all movies in IndexedDB (if collection exists)
    let movies = db.movies.count(function (value) 
        return (movies = value > 0 ? db.movies.toArray() : []);
    );

    //add new item to IndexedDb
    const submitMovie = (movie) => 
        db.movies.put( title: movie.title, rating: movie.rating );
    ;
</script>

<div class="main">
    <h1>Movie Journal</h1>

    <MovieInput on:submitMovie=(event) => submitMovie(event.detail.movie) />
    #await movies
        <div>Loading movies...</div>
    :then movieArray
        <MovieList movieArray />
    :catch error
        <div>Error loading movies: error.message</div>
    /await
</div>

<style>
    .main 
        width: 500px;
        max-width: 100%;
        padding: 1em;
        margin: auto;
        text-align: center;
    

    h1 
        color: #ff3e00;
        text-transform: uppercase;
        font-size: 4em;
        font-weight: 100;
    
</style>

添加 MovieList 也可能是我做错了什么:

还有 MovieList.svelte

<script>
    export let movieArray;
</script>

#each movieArray as movie
    <div>
        <h3>movie.title</h3>
        <p>Your Rating: movie.rating</p>
    </div>
/each

<style>
    div 
        text-align: left;
        padding-bottom: 10px;
        border-bottom: 1px solid black;
    
</style>

【问题讨论】:

考虑将声明 movies = db.movies.count ... 重构为更简单的 movies = loadMovies() 以避免在初始加载和添加电影后的刷新操作之间重复代码。 实际上,当我开始实现搜索功能时,我也这样做了!在我的问题末尾添加了更新的代码。感觉有点没必要一直获取数据库,所以在搜索时考虑使用一些临时数组,但目前它至少可以工作:) 【参考方案1】:

如果movies 持有可解析为电影数组的承诺,则 Svelte 方法是使用 #await ... 块:

<script>
    import MovieInput from "./MovieInput.svelte";
    import MovieList from "./MovieList.svelte";
    import Search from "./Search.svelte";
    import db from "./db.js";
    import Dexie from "dexie";

    // not needed, the resulting data array will be created within the
    // #await ... block
    // let movieArray = [];

    //get a promise containing all movies in IndexedDB (if collection exists)
    let movies = db.movies.count(function (value) 
        return (movies = value > 0 ? db.movies.toArray() : []);
    );

    // not needed, use an #await ... block to handle resolution or error 
    // push items in promise to movieArray
    // movies
    //    .then((movies) => 
    //        movies.forEach(function (movie) 
    //            movieArray.push(movie);
    //        );
    //    )
    //    .catch((error) => 
    //        console.log(error);
    //    ).finally(() => 
    //        movieArray = movieArray;
    //    );

    //add new item to IndexedDb
    const submitMovie = (movie) => 
        db.movies.put( title: movie.title, rating: movie.rating );
    ;
</script>

<div class="main">
    <h1>Movie Journal</h1>

    <MovieInput on:submitMovie=(event) => submitMovie(event.detail.movie) />
    #await movies
        <div>Loading movies...</div>
    :then movieArray
        <MovieList movieArray />
    :catch error
        <div>Error loading movies: error.message</div>
    /await
</div>

<style>
    ...
</style>

【讨论】:

嗨!谢谢,这确实删除了一些代码并且看起来更好,并且我已经验证它可以像这样工作,但是列表仍然需要手动页面刷新才能在屏幕上更新。 更新是什么意思?如果您正在更改数据库的内容并期望页面自动刷新,那么它不会发生。还是说初始渲染时列表为空,需要手动刷新页面才能看到数据? 现在我因为没有看到它而感到愚蠢:D 我只是在页面加载时获取集合,当然它不会更新,除非我刷新页面。感谢您指出! 感谢您提及我的小托马斯,我添加了在提交新项目时再次获取收藏,现在它(至少在视觉上)可以按我的意愿工作。

以上是关于苗条的反应性的主要内容,如果未能解决你的问题,请参考以下文章

结合反应性和事件反应性来生成绘图

减肥女性节食期禁食水果

Vue.js 3 - 替换/更新反应性对象而不会失去反应性

R 中的反应性问题 - 你试图做一些只能从反应性消费者内部完成的事情

以Vue为例,解释JavaScript的反应性

流星中的反应方法调用不是反应性的