在 Svelte 可读存储阵列中,如何只更新一个项目而不触及其他项目?
In a Svelte readable store array, How can I update only one item without touching the others?
我想这个问题更多的是关于 JS sysntax,但我有一个这样的存储数组:
export const store = readable( {id: 0, value: 0} , set => {
let socket = new WebSocket("ws://localhost:65432");
socket.onmessage = function (event) {
var data = JSON.parse(event.data);
set({id: 0, value: data});
}
})
商店定义了它的 set 方法来更新来自 websockets 连接的值。
我怎样才能做同样的事情,但使用商店阵列?类似于:
arr = [];
for(i=0; i<numberOfItems; i++) {
arr = [...arr,{id: i, value: 0}];
}
export const store = readable( [{arr}] , set => {
let socket = new WebSocket("ws://localhost:65432");
socket.onmessage = function (event) {
var data = JSON.parse(event.data);
var channel = data.channel;
set({id: data.channel, value: data.value});
}
})
这里是我无法 "set" 数组的地方,而且不必在每次更新时都声明整个数组。
我认为可读存储不会解决你的问题,因为你这里没有更新方法。为什么不试试 writable store 呢?它为您提供了一个以当前值作为参数的更新函数,因此您可以这样做:
let socket = new WebSocket("ws://localhost:65432");
socket.onmessage = function(event) {
var data = JSON.parse(event.data);
var channel = data.channel;
store.update(n => [...n, { id: data.channel, value: data.value }]);
};
这里有一个 REPL 以及它如何工作的示例。它使用间隔来模拟 webhooks 功能。如果你打开控制台,你可以看到更新后的存储值。
您也可以在回调中访问可读存储的实际值。然后你可以更新现有数组而不用全部替换:
<script>
import {readable} from 'svelte/store'
let intervalHandle
const arr = new readable(['Start'], (set) => {
intervalHandle = setInterval(() => {
set([...$arr, 'Another value'])
}, 1000)
})
</script>
<h1>Readable demo</h1>
<button on:click={() => clearInterval(intervalHandle)}>Stop it</button>
{#each $arr as item}
<div>{item}</div>
{/each}
我认为在你的情况下,你想要保存在商店中的不是一个数组,而是一个对象,这会让这一步更容易。类似于:
export const store = readable({} , set => {
let channels = {};
let socket = new WebSocket("ws://localhost:65432");
socket.onmessage = function ({data}) {
let { channel, value } = JSON.parse(data);
// update `channels`
channels = {...channels, [channel]: value };
// set the new `channels` as store value
set(channels)
}
})
请注意,通过这种方式,您将直接将频道作为对象的键:因此,如果频道已经存在,它将被更新而不是添加。如果不存在,则会添加。
因此,在您的订阅者中,您可以拥有类似的内容:
store.subscribe(channels => {
for (let [channel, value] of Object.entries(channels)) {
console.log(`channel ${channel} received ${value}`);
}
});
最后请注意,考虑到此代码每次更新都会创建一个新对象以避免副作用,这是常见的做法。
但是,如果对象中有大量数据并且您知道可能的含义,出于性能/内存原因,您可以只添加/更新单个键而不必每次都复制对象。
希望对您有所帮助!
我想这个问题更多的是关于 JS sysntax,但我有一个这样的存储数组:
export const store = readable( {id: 0, value: 0} , set => {
let socket = new WebSocket("ws://localhost:65432");
socket.onmessage = function (event) {
var data = JSON.parse(event.data);
set({id: 0, value: data});
}
})
商店定义了它的 set 方法来更新来自 websockets 连接的值。 我怎样才能做同样的事情,但使用商店阵列?类似于:
arr = [];
for(i=0; i<numberOfItems; i++) {
arr = [...arr,{id: i, value: 0}];
}
export const store = readable( [{arr}] , set => {
let socket = new WebSocket("ws://localhost:65432");
socket.onmessage = function (event) {
var data = JSON.parse(event.data);
var channel = data.channel;
set({id: data.channel, value: data.value});
}
})
这里是我无法 "set" 数组的地方,而且不必在每次更新时都声明整个数组。
我认为可读存储不会解决你的问题,因为你这里没有更新方法。为什么不试试 writable store 呢?它为您提供了一个以当前值作为参数的更新函数,因此您可以这样做:
let socket = new WebSocket("ws://localhost:65432");
socket.onmessage = function(event) {
var data = JSON.parse(event.data);
var channel = data.channel;
store.update(n => [...n, { id: data.channel, value: data.value }]);
};
这里有一个 REPL 以及它如何工作的示例。它使用间隔来模拟 webhooks 功能。如果你打开控制台,你可以看到更新后的存储值。
您也可以在回调中访问可读存储的实际值。然后你可以更新现有数组而不用全部替换:
<script>
import {readable} from 'svelte/store'
let intervalHandle
const arr = new readable(['Start'], (set) => {
intervalHandle = setInterval(() => {
set([...$arr, 'Another value'])
}, 1000)
})
</script>
<h1>Readable demo</h1>
<button on:click={() => clearInterval(intervalHandle)}>Stop it</button>
{#each $arr as item}
<div>{item}</div>
{/each}
我认为在你的情况下,你想要保存在商店中的不是一个数组,而是一个对象,这会让这一步更容易。类似于:
export const store = readable({} , set => {
let channels = {};
let socket = new WebSocket("ws://localhost:65432");
socket.onmessage = function ({data}) {
let { channel, value } = JSON.parse(data);
// update `channels`
channels = {...channels, [channel]: value };
// set the new `channels` as store value
set(channels)
}
})
请注意,通过这种方式,您将直接将频道作为对象的键:因此,如果频道已经存在,它将被更新而不是添加。如果不存在,则会添加。
因此,在您的订阅者中,您可以拥有类似的内容:
store.subscribe(channels => {
for (let [channel, value] of Object.entries(channels)) {
console.log(`channel ${channel} received ${value}`);
}
});
最后请注意,考虑到此代码每次更新都会创建一个新对象以避免副作用,这是常见的做法。 但是,如果对象中有大量数据并且您知道可能的含义,出于性能/内存原因,您可以只添加/更新单个键而不必每次都复制对象。
希望对您有所帮助!