反应性声明似乎不起作用?还是我以错误的方式使用"钩子"?



我正在用svelte-navigator编写SPA苗条应用程序。当pathname改变时,我想获取一个请求

import { useLocation } from "svelte-navigator";
import { useCallApi } from "./hook";
const loc = useLocation();
const [resp, fetchPageData] = useCallApi(); // my `hooks` to call api
$: pathname = $loc.pathname;
$: loading = $resp.loading;
$: data = $resp.data;
$: {
console.log("loading changed", loading);
}
$: if (pathname) {
console.log(pathname);
fetchPageData(); // when pathname change, call a api
}

fetchPageDatapathname每次变化时被调用,但反应性声明($: loading)不是每次更新。

我使用hooks的方式是这样的:

import { writable } from 'svelte/store';
export function useCallApi() {
let result = writable({
loading: false,
data: 0,
});
const fakeFetch = async () => {
result.update(pre => ({
data: 0,
loading: true,
}));

await new Promise(r => setTimeout(r, 500));

result.update(pre => ({
data: Math.random(),
loading: false,
}));
};
return [result, fakeFetch];
}

在线演示为https://svelte.dev/repl/e367c0aa3c9743cb8a749f92f0239d59?version=3.32.1。

单击To aTo b更改pathname时,响应式声明只更新一次。

但是当点击按钮trigger request时,所有状态更新都像我所期望的那样。

我想知道这是什么问题,svelte,svelte-navigatormy hooks?,为什么?

如果你能帮助我,我将非常感激。


更新:2021-02-02

我的朋友发现statements order影响了更新行为,这看起来有点像链接。如果把fetchPageData()放在顶部,更新行为看起来很好。

import { useLocation } from "svelte-navigator";
import { useCallApi } from "./hook";
const loc = useLocation();
const [resp, fetchPageData] = useCallApi();
//  the order is important which will affect the update behavior
$: if (pathname) {
console.log(pathname);
fetchPageData();
}
$: pathname = $loc.pathname;
$: loading = $resp.loading;
$: data = $resp.data;
$: {
console.log("loading changed", loading, $resp.loading);
}

我真的不知道为什么,但是当你用resp.subscribe()替换自动订阅$时,它会起作用:

import { useLocation } from "svelte-navigator";
import { useCallApi } from "./hook";
const loc = useLocation();
const [resp, fetchPageData] = useCallApi(); // my `hooks` to call api
$: pathname = $loc.pathname;
let loading;
let data;

resp.subscribe( result => {
loading = result.loading;
data = result.data;
});
$: {
console.log("loading changed", loading);
}
$: if (pathname) {
console.log(pathname);
fetchPageData(); // when pathname change, call a api
}

你可以在这里试试:https://svelte.dev/repl/ca065fdc188e41938b8e3db0b8c61f20?version=3.32.1

我认为答案就在svelte执行反应性语句的方式后面。

根据:https://stackoverflow.com/a/63977760/12153710:

svelte批处理所有的更改,以便在下一个更新周期中更新它们,并且在更新DOM之前,它将执行响应声明来更新响应变量。

当你从a更新你的路由器时,我认为编译后的代码在更新响应性语句$: loading = $resp.loading;$: data = $resp.data;之前等待承诺解决(在hook.js),因此{ loading }{ data }为DOM。

最新更新