BuilderIO / BuilderIO/builder

EnableEditor state merging breaks reactivity of blocks in Qwik

Open
#4,191 0 comments 0 reactions 1 assignee Claimed by @sanyamkamat View on GitHub
Dominant language
TypeScript
Stars
8.8k
Forks
1.2k
Avg merge
1d 6h
Merged PRs (30d)
17

Description

In qwik, if you have 2x simple components and have them added to Builder as blocks:
- Tab (provides a context for what is selected)
- TabPane (reads context and does a hide/show)

You'll see that reactivity breaks when EnableEditor comes alive (you're editing in Builder or previewing). This is how the EnableEditor component is merging the new content:

https://github.com/BuilderIO/builder/blob/main/packages/sdks/src/components/content/components/enable-editor.lite.tsx#L129-L144

You can fix it by copying how Qwik REPL does a deepUpdate (tested and verified it works): https://github.com/QwikDev/qwik/blob/main/packages/docs/src/repl/ui/repl-output-update.ts

Then it's as simple as:
```ts
import { unwrapStore } from '@builder.io/qwik';

const deepUpdate = (prev: any, next: any) => {
for (const key in next) {
if (prev[key] && typeof next[key] === 'object' && typeof prev[key] === 'object') {
deepUpdate(prev[key], next[key]);
} else {
if (unwrapStore(prev[key]) !== next[key]) {
prev[key] = next[key];
}
}
}
if (Array.isArray(prev)) {
if (prev.length !== next.length) {
prev.length = next.length;
}
} else {
for (const key in prev) {
if (!(key in next)) {
delete prev[key];
}
}
}
};

mergeNewContent(newContent: BuilderContent, editType?: EditType) {
deepUpdate(props.builderContextSignal.content, newContent);
}
```

And you have reactivity again in both default/editing mode.

Example of tabs with a context for which one is visible:
```tsx
import { component$, createContextId, Signal, Slot, useContext, useContextProvider, useSignal } from '@builder.io/qwik';

const tabContextId = createContextId>('active-tab-slug');

interface TabHeader {
slug: string;
text: string;
}

export const Tabs = component$(({ tabs }: { tabs: TabHeader[] }) => {
const activeTabSlug = useSignal('one');
useContextProvider(tabContextId, activeTabSlug);

return (



{tabs.map(tab => activeTabSlug.value = tab.slug}>{tab.text})}



)
});

export const TabPane = component$(({ slug }: { slug: string }) => {
const active = useContext(tabContextId);

return (




)
});
```

And then via Builder CMS you can have blocks that provide a structure like this:
```tsx






```

You won't be able to click between those tabs within Builder when editing. I think it works once but then breaks.

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.