EnableEditor state merging breaks reactivity of blocks in Qwik
- 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.