I have an object that I loop over with an each block. When I hover, I temporarily change a property on the actual object entry and use it to assign a class. This works fine, but it also causes other reactivity to be triggered unnecessarily often.
<script>
let things = [
{ id: 1, name: 'apple' },
{ id: 2, name: 'banana' },
{ id: 3, name: 'carrot' },
{ id: 4, name: 'doughnut' },
{ id: 5, name: 'egg' },
];
function makePretty(somethings) {
const prettyThings = somethings.map(thing => thing.name).join(' ');
console.log(prettyThings);
return prettyThings;
}
$: prettyThings = makePretty(things)
</script>
<ul>
{#each things as thing (thing.id)}
<li
class:hover={thing.hover}
on:mouseenter={() => (thing.hover = true)}
on:mouseleave={() => (thing.hover = false)}
>
{thing.name}
</li>
{/each}
</ul>
<style>
.hover {
background-color: cyan;
}
</style>
REPL: https://svelte.dev/repl/c658cccd0bc2471a8f9c4758387340c5?version=3.48.0 n the console, you can see how often the reactivity on the prettyThings is triggered when you move over the list with your mouse.
I do realise that this is expected behaviour, as the 'things'-object is effectively changed on every mouseenter and mouseleave. And thus the prettyThings is called every time.
What would be an ideomatic way to apply a hover to a 'row' from an array of objects, without changing the object itself? In doing so, the object should still be live modifiable by other operations (e.g. add, delete, ...).
CodePudding user response:
you can use css only to achieve this:
<script>
let things = [
{ id: 1, name: 'apple' },
{ id: 2, name: 'banana' },
{ id: 3, name: 'carrot' },
{ id: 4, name: 'doughnut' },
{ id: 5, name: 'egg' },
];
function makePretty(somethings) {
const prettyThings = somethings.map(thing => thing.name).join(' ');
console.log(prettyThings);
return prettyThings;
}
$: prettyThings = makePretty(things)
</script>
<ul>
{#each things as thing (thing.id)}
<li>
{thing.name}
</li>
{/each}
</ul>
<style>
li:hover {
background-color: cyan;
}
</style>
REPL: https://svelte.dev/repl/9590df9f09334adda571e6cf8ddb34ce?version=3.48.0
CodePudding user response:
One way to do this, would be to split the rendering into a separate component.
<script>
export let thing;
</script>
<li class:hover={thing.hover}
on:mouseenter={() => (thing.hover = true)}
on:mouseleave={() => (thing.hover = false)} >
{thing.name}
</li>
<style>
.hover {
background-color: cyan;
}
</style>
{#each things as thing (thing.id)}
<ItemDisplay {thing} />
{/each}
Maybe there are better approaches, though.