-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Change copy/design/layout, add experiment support, fix rendering edge…
… cases, dedicated hydration examples
- Loading branch information
Showing
27 changed files
with
591 additions
and
334 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
"use client"; | ||
import Cookies from "js-cookie"; | ||
import { AutoExperiment, FeatureDefinition } from "@growthbook/growthbook"; | ||
import { gb, setPayload } from "@/lib/growthbookClient"; | ||
import { GrowthBookProvider } from "@growthbook/growthbook-react"; | ||
import ClientComponent from "./ClientComponent"; | ||
import { GB_UUID_COOKIE } from "@/middleware"; | ||
import { useCallback, useEffect, useMemo, useRef } from "react"; | ||
|
||
export default function ClientApp({ | ||
payload, | ||
}: { | ||
payload: { | ||
features: Record<string, FeatureDefinition<unknown>>; | ||
experiments: AutoExperiment[]; | ||
}; | ||
}) { | ||
// Helper to hydrate client-side GrowthBook instance with payload from the server | ||
const hydrate = useCallback(() => { | ||
setPayload(payload); | ||
gb.setAttributes({ | ||
id: Cookies.get(GB_UUID_COOKIE), | ||
}); | ||
}, [payload]); | ||
|
||
// Hydrate immediately on first render and whenever the payload changes | ||
const ref = useRef<boolean>(); | ||
if (!ref.current) { | ||
ref.current = true; | ||
hydrate(); | ||
} | ||
useEffect(() => hydrate(), [hydrate]); | ||
|
||
return ( | ||
<GrowthBookProvider growthbook={gb}> | ||
<ClientComponent /> | ||
</GrowthBookProvider> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
"use client"; | ||
import RevalidateMessage from "@/app/revalidate/RevalidateMessage"; | ||
import { useFeatureIsOn, useFeatureValue } from "@growthbook/growthbook-react"; | ||
|
||
export default function ClientComponent() { | ||
const feature1Enabled = useFeatureIsOn("feature1"); | ||
const feature2Value = useFeatureValue("feature2", "fallback"); | ||
return ( | ||
<div> | ||
<h2>Optimized Client Rendering</h2> | ||
<p> | ||
This page fetches feature flags and experiments at build time, but waits | ||
to evaluate them until client-side rendering. This gives you flexibility | ||
while avoiding flicker. | ||
</p> | ||
<ul> | ||
<li> | ||
feature1: <strong>{feature1Enabled ? "ON" : "OFF"}</strong> | ||
</li> | ||
<li> | ||
feature2: <strong>{feature2Value}</strong> | ||
</li> | ||
</ul> | ||
|
||
<RevalidateMessage /> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { getInstance, getPayload } from "@/lib/growthbookServer"; | ||
import ClientApp from "./ClientApp"; | ||
|
||
export default async function PrerenderedClientPage() { | ||
// Get server-side GrowthBook instance in order to fetch the feature flag payload | ||
const gb = await getInstance(); | ||
|
||
return <ClientApp payload={getPayload(gb)} />; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
"use client"; | ||
import Cookies from "js-cookie"; | ||
import { AutoExperiment, FeatureDefinition } from "@growthbook/growthbook"; | ||
import { gb, setPayload } from "@/lib/growthbookClient"; | ||
import { GrowthBookProvider } from "@growthbook/growthbook-react"; | ||
import ClientComponent from "./ClientComponent"; | ||
import { GB_UUID_COOKIE } from "@/middleware"; | ||
import { useCallback, useEffect, useRef } from "react"; | ||
|
||
export default function ClientApp({ | ||
payload, | ||
}: { | ||
payload: { | ||
features: Record<string, FeatureDefinition<unknown>>; | ||
experiments: AutoExperiment[]; | ||
}; | ||
}) { | ||
// Helper to hydrate client-side GrowthBook instance with payload from the server | ||
const hydrate = useCallback(() => { | ||
setPayload(payload); | ||
gb.setAttributes({ | ||
id: Cookies.get(GB_UUID_COOKIE), | ||
}); | ||
}, [payload]); | ||
|
||
// Hydrate immediately on first render and whenever the payload changes | ||
const ref = useRef<boolean>(); | ||
if (!ref.current) { | ||
ref.current = true; | ||
hydrate(); | ||
} | ||
useEffect(() => hydrate(), [hydrate]); | ||
|
||
return ( | ||
<GrowthBookProvider growthbook={gb}> | ||
<ClientComponent /> | ||
</GrowthBookProvider> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
"use client"; | ||
import { useFeatureIsOn, useFeatureValue } from "@growthbook/growthbook-react"; | ||
|
||
export default function ClientComponent() { | ||
const feature1Enabled = useFeatureIsOn("feature1"); | ||
const feature2Value = useFeatureValue("feature2", "fallback"); | ||
return ( | ||
<div> | ||
<p>And these features are rendered client-side:</p> | ||
<ul> | ||
<li> | ||
feature1: <strong>{feature1Enabled ? "ON" : "OFF"}</strong> | ||
</li> | ||
<li> | ||
feature2: <strong>{feature2Value}</strong> | ||
</li> | ||
</ul> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import { getInstance, getPayload } from "@/lib/growthbookServer"; | ||
import { cookies } from "next/headers"; | ||
import { GrowthBookTracking } from "@/lib/growthbookClient"; | ||
import { GB_UUID_COOKIE } from "@/middleware"; | ||
import ClientApp from "./ClientApp"; | ||
import RevalidateMessage from "@/app/revalidate/RevalidateMessage"; | ||
|
||
export default async function ServerCombo() { | ||
// create instance per request, server-side | ||
const gb = await getInstance(); | ||
|
||
// using cookies means next will render this page dynamically | ||
gb.setAttributes({ | ||
id: cookies().get(GB_UUID_COOKIE)?.value || "", | ||
}); | ||
|
||
const feature1Enabled = gb.isOn("feature1"); | ||
const feature2Value = gb.getFeatureValue("feature2", "fallback"); | ||
|
||
return ( | ||
<div> | ||
<h2>Server / Client Hybrid</h2> | ||
<p> | ||
This page fetches and uses feature flags server-side, then hydrates the | ||
client-side GrowthBook instance. This gives you maximum flexibility and | ||
performance. | ||
</p> | ||
<p>These features were rendered server-side:</p> | ||
<ul> | ||
<li> | ||
feature1: <strong>{feature1Enabled ? "ON" : "OFF"}</strong> | ||
</li> | ||
<li> | ||
feature2: <strong>{feature2Value}</strong> | ||
</li> | ||
</ul> | ||
|
||
<ClientApp payload={getPayload(gb)} /> | ||
|
||
<RevalidateMessage /> | ||
|
||
<GrowthBookTracking data={gb.getDeferredTrackingCalls()} /> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.