Svelte:传递已声明的函数时,反应式声明不起作用

Svelte: Reactive declaration does not work when passing a declared function

问题

我创建了一个 reactive 变量来在 state 变量发生变化时对数组进行排序。如果我直接将 sort 函数声明为回调,它确实有效,但如果我传递一个已经声明的函数则无效。

代码

所以这是工作的代码:

  const sortSongs = (a, b) => {
        const [option, direction] = sortOption.split("-");
        const itemA = a[option == "Song" ? "title" : "artist"].toLowerCase();
        const itemB = b[option == "Song" ? "title" : "artist"].toLowerCase();

        if (itemA < itemB) {
          return direction == "up" ? 1 : -1;
        }

        if (itemA > itemB) {
          return direction == "up" ? -1 : 1;
        }

    return 0;
  };

  $: filteredSongs =
    lessons
      ?.sort(sortSongs)
      .filter(lesson => lesson.title?.toLowerCase().includes(value)) || [];

这就是工作的人:

  $: filteredSongs =
    lessons
      ?.sort((a, b) => {
        const [option, direction] = sortOption.split("-");
        const itemA = a[option == "Song" ? "title" : "artist"].toLowerCase();
        const itemB = b[option == "Song" ? "title" : "artist"].toLowerCase();

        if (itemA < itemB) {
          return direction == "up" ? 1 : -1;
        }

        if (itemA > itemB) {
          return direction == "up" ? -1 : 1;
        }

        return 0;
      })
      .filter(lesson => lesson.title?.toLowerCase().includes(value)) || [];

混乱

所以不应该两者都起作用吗?为什么我声明函数的地方会有所不同?这是一个 REPL 以查看实际效果。红色的歌曲有无效代码,绿色的歌曲有有效代码。

您希望 $: filteredSongssortOption 更改时重新计算,但是当您传递函数引用 .sort(sortSongs) 时,sortOption 在函数内部是 'hidden' 并且不再与反应式陈述直接相关。 second paragraph

中的文档中提到了它

Only values which directly appear within the $: block will become dependencies of the reactive statement

一个快速而肮脏的解决方案是将 sortOption 作为参数传递

?.sort(sortSongs, sortOption)

.sort() 只期望比较函数作为参数,因此 sortOption 将被忽略,但又是一个依赖项,因为在 $: 块中再次

如果不使用 'redundant' 参数调用 .sort(),这将是一个更清晰的替代方案

let lessons = [];
...

const sortSongs = (songs, sortOption) => {
        return songs.sort((a,b) => {
            const [option, direction] = sortOption.split("-");
            const itemA = a[option == "Song" ? "title" : "artist"].toLowerCase();
            const itemB = b[option == "Song" ? "title" : "artist"].toLowerCase();

            if (itemA < itemB) {
                return direction == "up" ? 1 : -1;
            }

            if (itemA > itemB) {
                return direction == "up" ? -1 : 1;
            }

            return 0;
        })     
    };

    $: filteredSongs =
        sortSongs(lessons, sortOption)
        .filter(lesson => lesson.title?.toLowerCase().includes(value));