Svelte基础
Svelte高阶
上下文API
特殊元素
接下来
SvelteKit基础
Shared modules
API routes
$app/state
Errors and redirects
Advanced SvelteKit
Page options
Link options
Advanced routing
Advanced loading
Environment variables
Conclusion
恭喜小主,开启了高级功法💕💕💕 在先前的练习中我们学到状态是深度响应的——当修改一个对象的某个属性或者往数组中添加元素时都会引起UI更新。这是通过创建代理拦截读写操作实现的。
In previous exercises, we learned that state is deeply reactive — if you (for example) change a property of an object, or push to an array, it will cause the UI to update. This works by creating a proxy that intercepts reads and writes.
有时候这可能不是你想要的。比如你并不想修改某个属性或者需要保持引用相等,这个时候你可以使用 raw状态 。 不愧是高阶功法,就是拗口, 没点悟性和耐心还真参悟不了。 也就是只在用新状态替换原来的状态时才更新UI,我们就不需要通过 修改 原状态更新UI。 举个栗子🌰: 做一个持续显示股票价格的图表(曲线图)。只有当获取到新数据时才更新图表:
Occasionally, that’s not what you want. If you’re not changing individual properties, or if it’s important to maintain referential equality, then you can use raw state instead. In this example, we have a chart of Svelte’s steadily increasing stock price. We want the chart to update when new data comes in, which we could achieve by turning
data
into state...
let data = $state(poll());
虽然也能达到效果,但勤俭持家的小主是不是觉得有点浪费了, 毕竟这里使用深度响应是没有意义的,因为新数据很快就会到,原来的数据也很快会被丢弃。可以使用$state.raw
:
...but there’s no need to make it deeply reactive when it will be discarded a few milliseconds later. Instead, use
$state.raw
:
let data = $state.raw(poll());
修改Raw状态是没有效应的. 通常我们也不应该不推荐修改非响应状态。
Mutating raw state will have no direct effect. In general, mutating non-reactive state is strongly discouraged.
<script>
import { scale } from './utils.js';
import { poll } from './data.js';
let data = poll();
let w = $state(1);
let h = $state(1);
const min = $derived(Math.min(...data) - 5);
const max = $derived(Math.max(...data) + 5);
const x = $derived(scale([0, data.length], [0, w]));
const y = $derived(scale([min, max], [h, 0]));
const ticks = $derived.by(() => {
const result = [];
let n = 10 * Math.ceil(min / 10);
while (n < max) {
result.push(n);
n += 10;
}
return result;
});
$effect(() => {
const interval = setInterval(() => {
data = poll();
}, 200);
return () => {
clearInterval(interval);
};
});
</script>
<div class="outer">
<svg width={w} height={h} bind:clientWidth={w} bind:clientHeight={h}>
<line y1={h} y2={h} x2={w} />
{#each ticks as tick}
<g class="tick" transform="translate(0,{y(tick)})">
<line x2={w} />
<text x={-5}>{tick}</text>
</g>
{/each}
<polyline points={data.map((d, i) => [x(i), y(d)]).join(' ')} />
<text x={10} y={10} font-size={36}>$SVLT</text>
</svg>
</div>
<style>
.outer {
width: 100%;
height: 100%;
padding: 2em;
box-sizing: border-box;
}
svg {
width: 100%;
height: 100%;
overflow: visible;
}
polyline {
fill: none;
stroke: #ff3e00;
stroke-width: 2;
stroke-linejoin: round;
stroke-linecap: round;
}
line {
stroke: #aaa;
}
.tick {
stroke-dasharray: 2 2;
text {
text-anchor: end;
dominant-baseline: middle;
}
}
</style>