Skip to content

Commit 8172e62

Browse files
committed
fix: resolve dynamic templates to inner component before rendering to prevent hydration mismatches and double renders
1 parent 9f37169 commit 8172e62

5 files changed

Lines changed: 32 additions & 24 deletions

File tree

.changeset/shaky-toes-open.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@faustwp/core': patch
3+
---
4+
5+
Fixed an issue where dynamic template components were rendered via the next/dynamic wrapper directly, causing hydration mismatches and double renders, by resolving the dynamic component to its inner function and storing it in state before rendering.

examples/next/faustwp-getting-started/wp-templates/category.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ const GET_CATEGORY_QUERY = gql`
4343

4444
export default function Component(props) {
4545
const { generalSettings, headerMenuItems, footerMenuItems } =
46-
useFaustQuery(GET_LAYOUT_QUERY);
46+
useFaustQuery(GET_LAYOUT_QUERY) ?? {};
4747
const { nodeByUri } = useFaustQuery(GET_CATEGORY_QUERY) ?? {};
4848

4949
const { title: siteTitle, description: siteDescription } =

examples/next/faustwp-getting-started/wp-templates/index.js

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,10 @@
11
import dynamic from 'next/dynamic';
22
import { default as FrontPage } from './front-page.js';
33

4-
const category = dynamic(() => import('./category.js'), {
5-
loading: () => <p>Loading Category Template...</p>,
6-
ssr: false,
7-
});
8-
9-
const tag = dynamic(() => import('./tag.js'), {
10-
loading: () => <p>Loading Tag Template...</p>,
11-
ssr: false,
12-
});
13-
14-
const page = dynamic(() => import('./page.js'), {
15-
loading: () => <p>Loading Page Template...</p>,
16-
ssr: false,
17-
});
18-
19-
const single = dynamic(() => import('./single.js'), {
20-
loading: () => <p>Loading Single Post Template...</p>,
21-
ssr: false,
22-
});
4+
const category = dynamic(() => import('./category.js'));
5+
const tag = dynamic(() => import('./tag.js'));
6+
const page = dynamic(() => import('./page.js'));
7+
const single = dynamic(() => import('./single.js'));
238

249
export default {
2510
category,

examples/next/faustwp-getting-started/wp-templates/page.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const GET_PAGE_QUERY = gql`
2626

2727
export default function Component(props) {
2828
// Loading state for previews
29-
if (props.loading) {
29+
if (props?.loading) {
3030
return <>Loading...</>;
3131
}
3232

packages/faustwp-core/src/components/WordPressTemplate.tsx

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,10 @@ export function WordPressTemplateInternal(
7676
...wordpressTemplateProps
7777
} = props;
7878
const unknownTemplate = getTemplate(seedNode, templates);
79+
const isDynamic = isDynamicComponent(unknownTemplate);
7980
const [data, setData] = useState<any | null>(templateQueryDataProp);
81+
const [resolvedTemplate, setResolvedTemplate] =
82+
useState<WordPressTemplateType | null>(null);
8083
const { setQueries } = useContext(FaustContext) || {};
8184

8285
/**
@@ -88,7 +91,7 @@ export function WordPressTemplateInternal(
8891
return;
8992
}
9093

91-
const template = isDynamicComponent(unknownTemplate)
94+
const template = isDynamic
9295
? await loadDynamicComponent(unknownTemplate)
9396
: unknownTemplate;
9497

@@ -152,7 +155,7 @@ export function WordPressTemplateInternal(
152155
return;
153156
}
154157

155-
const template = isDynamicComponent(unknownTemplate)
158+
const template = isDynamic
156159
? await loadDynamicComponent(unknownTemplate)
157160
: unknownTemplate;
158161

@@ -185,11 +188,26 @@ export function WordPressTemplateInternal(
185188
})();
186189
}, [data, unknownTemplate, seedNode, isPreview, isAuthenticated, setLoading]);
187190

191+
useEffect(() => {
192+
if (!unknownTemplate || !isDynamic) {
193+
return;
194+
}
195+
void loadDynamicComponent(unknownTemplate).then((template) => {
196+
setResolvedTemplate(() => template);
197+
});
198+
}, [unknownTemplate]);
199+
188200
if (!unknownTemplate) {
189201
return null;
190202
}
191203

192-
const Component = unknownTemplate as React.FC<{ [key: string]: any }>;
204+
if (isDynamic && !resolvedTemplate) {
205+
return null;
206+
}
207+
208+
const Component = (
209+
isDynamic ? resolvedTemplate : unknownTemplate
210+
) as React.FC<{ [key: string]: any }>;
193211
const newProps = {
194212
...wordpressTemplateProps,
195213
__TEMPLATE_QUERY_DATA__: templateQueryDataProp,

0 commit comments

Comments
 (0)