#Property spreading / destructuring, useStore, or pass store.

16 messages · Page 1 of 1 (latest)

trim kernel
#

I've been trying to find a pattern to allow reactivity when I don't know which properties are to be passed down.

It seems that reactivity is lost using {...props} type spreading. (in this case props is a Store).

I saw in one conversation that passing whole stores instead of props is a pattern used in qwik, but the linked article is 404.

What's the best practice here?

ripe gazelle
trim kernel
#

Let me drop some code here:

export default component$<LabProps>(({ schema, prototype, component }) => {
    const value = useStore(prototype);
.
.
.
                    <div ref={componentContainer}>
                        <LabComponent {...value} />
                        <LabComponent label={value.label} />
                    </div>
#

In the top LabComponent, no reactivity is observered, in the latter, it is

#

I'm guessing the 'pass the store' pattern would look like this?

                        <LabComponent properties={value} />
ripe gazelle
#

Yeah so Qwik here doesn't know which properties you're using within the child component. You need to explicitly pass properties or the store.

// Parent.tsx
import { component$, useStore } from '@builder.io/qwik';

export default component$(() => {
  const store = useStore({
    label: 'Hello, Qwik!',
    // ... other properties
  });

  return (
    <Child store={store} />
  );
});

// Child.tsx
import { component$, useStore, useTask$ } from '@builder.io/qwik';

export const Child = component$((props) => {
  const store = useStore(props.store);

  // if you want to track someting
  useTask$(({ track }) => {
     track(() => // signal or store to track)
    // ... react to changes
  });

  return (
    <div>
      {store.label}
    </div>
  );
});
#

Personally I would use a signal over a store whenever possible

#

And a signal or store with context

#

Which is my preferred approach

trim kernel
#

Right, well my use case is creating a 'Storybook' type component, that needs to be able to render other "normal" components without knowning much about them. I can use the 'pass the store' approach, though it requires all components to be aware of it. I suppose I'll add an extra property to all components that can accept a store, and have each component be aware to use the store if present.

ripe gazelle
#

then you can consume it with context.myStore.label for example without needing to prop drill everything

trim kernel
#

Well it's only one level deep so its a bit extra to make the context.

patent crest
#

I don't know but try not to destruct the props if you want to track it down, i mean user it like props.prototype instead of prototype, This might do the trick.

trim kernel
#

This is the pattern I've decided to go with:

export interface PropState<T> {
    state?: T;
}

export type Props = {
    propA: string;
    propB: number;
}

export default component$<Props & PropState<Props>>((props) => {
    const { propA, propB } = props.state ?? props;
    ...
}