typescript - Hur muterar jag enkelt arrayen inuti en signal


Det här är ett fungerande exempel, med ett problem. Jag vill splica en befintlig array inuti ett signal, och returnera den för att se den uppdaterad. Men det fungerar inte. Hur muterar jag enkelt arrayen inuti ett signal? Jag vill inte skapa nya arrays, bara en enkel splice. Det finns inget exempel i dokumentationen om att mutera en array.

import {  render } from 'solid-js/web';
import { createSignal, createEffect } from 'solid-js'

function HelloWorld() {
  let [a, setA] = createSignal([])

  setTimeout(() => 
  setA(a => {
    a.splice(0, 0, 'hello')
    // this logs as requested if I uncomment this
    //return ['hello']
    return a
  }))


  createEffect(() => {
    console.log(a())
  })
  return <div>Hello World!</div>;
}

render(() => <HelloWorld />, document.getElementById('app'))

Svar #1

Solid-handledningen rekommenderar starkt oföränderlighet:

Solid rekommenderar starkt användningen av grunda oföränderliga mönster för att uppdatera tillstånd. Genom att separera läsningar och skrivningar behåller vi bättre kontroll över systemets reaktivitet utan risken att tappa bort förändringar i vår proxy när den passerar genom komponentlager.

Ett oföränderligt sätt att uppnå det du strävar efter kan se ut ungefär så här:

setA(a => ['hello', ...a])

Om du däremot bestämmer att du måste mutera signalen, kan du specificera hur Solid avgör om en signal har uppdaterats inom createSignals options-objekt. Som standard jämförs signaländringar med referenslikhet med hjälp av ===-operatorn. Du kan tala om för Solid att alltid köra om beroenden efter att setter-funktionen har kallats genom att sätta equals till false:

let [a, setA] = createSignal([], { equals: false });

Eller så kan du skicka en funktion som tar previous och next-värdena av signalen och returnerar en boolean:

let [a, setA] = createSignal([], { equals: (prev, next) => {
  if (/* dependents should run */) {
    return false;
  }
  // dependents shouldn't run
  return true;
} });

Svar #2

Varning: Jag är ny på Solid.js och Javascript/Typescript i allmänhet. Det jag har gjort nedan kan vara en riktigt dålig idé.

Jag stötte på samma problem och kom fram till följande. Det verkar fungera. I princip, behåll värdet (t.ex. en mycket stor array) i en lättviktsinbäddad typ. Återskapa den inbäddade typen istället för att återskapa arrayen. Funktionen createSignalMutable nedan returnerar en getter-funktion som returnerar det utpackade värdet, och en uppdateringsfunktion som uppdaterar det utpackade värdet.

import { render } from "solid-js/web";
import { createSignal, createEffect } from "solid-js";

type ThinWrapper<T> = {
  internal: T;
};

function createSignalMutable<T>(value: T) {
  let [getter, setter] = createSignal<ThinWrapper<T>>({ internal: value });

  let getUnwrapped = () => getter().internal;

  let updateUnwrapped = (mutator: (value: T) => void) =>
    setter((oldWrapped: ThinWrapper<T>) => {
      mutator(oldWrapped.internal);
      let newWrapped: ThinWrapper<T> = { internal: value };
      return newWrapped;
    });

  return [getUnwrapped, updateUnwrapped];
}

let initialValue: number[] = [];
let [numbers, updateNumbers] = createSignalMutable(initialValue);

createEffect(() => {
  console.log("Array length is now ", [...numbers()].length);
});

updateNumbers((val) => val.push(1));
updateNumbers((val) => val.push(2));

Detta kommer att skriva ut

Array length is now  0
Array length is now  1
Array length is now  2

Länk till lekplats här.

Relaterade artiklar