typescript - Svelte Flere app-instansene med Stores. (uten Redux)


merk:- selv besvart

Så som standard finnes det tre hovedmåter i Svelte som du kan bruke for å sende data mellom forskjellige komponenter.

1. Det åpenbare, ved å bruke rekvisitter

Send data fra en overordnet til et barn.

  1. Énveis dataoverføring kun.
  2. Går bare mellom to foreldre-barn-komponenter. Må være et direkte barn.

2. Sette opp og bruke kontekst

Kan sende data fra overordnet til hvilken som helst dyp barnekomponent.

  1. Énveis dataflyt
  2. Kan ikke sende data fra utenfor forelder-barn-hierarkiet.
  3. Må settes opp når foreldreskomponenten startes.

3. Ved å bruke svelte Store

Kan sette, oppdatere og bruke/abonnere på data fra/i hvilken som helst fil eller komponent.

  1. Hvis flere forekomster av den samme appen kjører, vil butikken bare lagre én verdi fra en av forekomstene. storeVar.set() setter verdien fra en av forekomstene avhengig av sideinnlastningstiden. storeVar.update() setter verdien fra den siste forekomsten.

Mål

Sett opp en Svelte-app for å oppdage flere tilpassede innebyggingskoder fra rotindeksen og kjøre flere instanser av appen. Innebyggingskoden vil ha ekstra data - videostørrelse, sideforhold osv. Så hver instansens brukergrensesnitt vil endre seg avhengig av attributtene til den innebygde koden (sendt som props til App). På brukergrensesnittet kan brukeren klikke på forskjellige handlinger som skjermstørrelser, og i så fall må jeg oppdatere App-verdiene (props sendt fra index til App) kun for den instansen og ikke for de andre.

Problem

Fra de ovennevnte problemene, enten kan jeg ikke sende eller oppdatere verdiene senere i komponentene (problem 2.2, 2.3) ELLER så lagrer ikke butikken hver enkelt verdi (3.1)

Svar #1

Løsning (testet og fungerer)

I hovedsak opprettet jeg et array med objekter med instansen id og data. Bruk update() i stedet for set(). Jeg filtrerer det nye instansobjektet fra arrayet før jeg legger til de nye dataene for samme instans.

Kode(typescript)

package.json

"scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview",
    "check": "svelte-check --tsconfig ./tsconfig.json"
  },
  "devDependencies": {
    "@sveltejs/vite-plugin-svelte": "^1.0.0-next.30",
    "@tsconfig/svelte": "^2.0.1",
    "autoprefixer": "^10.4.7",
    "cssnano": "^5.1.10",
    "postcss": "^8.4.14",
    "svelte": "^3.44.0",
    "svelte-check": "^2.2.7",
    "svelte-preprocess": "^4.9.8",
    "tailwindcss": "^3.0.24",
    "tslib": "^2.3.1",
    "typescript": "^4.5.4",
    "vite": "^2.9.9"
  },
  "dependencies": {
    "swiper": "^8.2.2"
  }

Index.html

  <body>
    <custom-element
      id="id_custom_element_987654321"
      videoid="987654321"
      size="7"
    ></custom-element>
    <script type="module" src="/src/main.ts"></script>
    <custom-element
      id="id_custom_element_123456789"
      videoid="123456789"
      size="3"
    ></custom-element>
    <script type="module" src="/src/main.ts"></script>
  </body>

main.ts

const embedElements = document.querySelectorAll(
  "custom-element"
);

const app = embedElements.forEach((each) => {
  //  @ts-ignore
  const elementId = each.attributes.id;
  //  @ts-ignore
  const videoid = each.attributes.videoid;

  if (elementId && videoid) {
    return new App({
      target: each,
      props: {
        embedElementId: elementId.value,
        embedVideoid: videoid.value,
      },
    });
  }
});

export default app;

helpers.ts

// Svelte helpers
export type CustomStoreFormatType<K> = {
  videoid: string;
  data: K;
};

export type StoreKeyType<L> = Writable<CustomStoreFormatType<L>[]>;

export const custom_updateStore = <T>(
  storeKey: StoreKeyType<T>,
  updateValue: CustomStoreFormatType<T>
) => {
  storeKey.update((old) => [
    ...old.filter(
      (e) => e.videoid !== updateValue.videoid
    ),
    { ...updateValue },
  ]);
};

export const custom_getStore = <T>(
  storeKey: CustomStoreFormatType<T>[],
  videoid: string
) =>  storeKey.find((e) => e.videoid === videoid);

store.ts

type CommonCustomStoreFormatType<T> = Array<CustomStoreFormatType<T>>;

export const store_videoComments = writable<
  CommonCustomStoreFormatType<Array<VideoCommentsType>>
>([]);

App.svelte

// passed props
  export let embedElementId: string;
  export let embedVideoid: string;
  setContext("contxt_videoid", embedVideoid);

  let videoComments = fetchvideoComments(embedVideoid);
  videoComments.then(({ data }) => {
    custom_updateStore<VideoCommentsType[]>(store_videoComments, {
      videoId: data.id,
      data: data.comments,
    });
  });
</script>

<main>
  {#await videoData}
    <LoaderCircular --color="green" />
  {:then { data }}
    <Video />
  {:catch error}
    <p style="color: red">{error.message}</p>
  {/await}
</main>

enhver annen komponent (hent butikkforekomstverdi)

  import { store_videoComments } from "./store";

  const videoId = getContext("contxt_videoId");
  let { data } = custom_getStore(
    $store_videoComments,
    videoId as string
  );

Utdata - logging $store_videoComments

[
    {
        "videoId": "987654321",
        "data": "[data1,data2,data3]"
    },
    {
        "videoId": "123456789",
        "data": "[data63,data74,data88]"
    }
]


Som du kan se fra loggen, blir alle app-instansers verdier lagret. Gi meg beskjed i kommentarfeltet hvis du har funnet noen problemer med metoden ovenfor ELLER vet/brukt et bedre alternativ for alt dette.

Merk:

  • Jeg ønsket å holde byggets størrelse så lav som mulig, så jeg søkte ikke etter/inkluderte noen tredjepartspakker for å håndtere problemet.
  • Jeg har ikke brukt SvelteKit
  • samme lagt ut på github-svelte-discussion