我正在用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
}
fetchPageData
在pathname
每次变化时被调用,但反应性声明($: 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 a
或To b
更改pathname
时,响应式声明只更新一次。
但是当点击按钮trigger request
时,所有状态更新都像我所期望的那样。
我想知道这是什么问题,svelte
,svelte-navigator
或my 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。