diff --git a/next-js/src/app/client/ClientComponent.tsx b/next-js/src/app/client/ClientComponent.tsx
new file mode 100644
index 0000000..6f7da0b
--- /dev/null
+++ b/next-js/src/app/client/ClientComponent.tsx
@@ -0,0 +1,24 @@
+"use client";
+import { useFeatureIsOn, useFeatureValue } from "@growthbook/growthbook-react";
+export default function ClientComponent() {
+ const feature1Enabled = useFeatureIsOn("feature1");
+ const feature2Value = useFeatureValue("feature2", "fallback");
+ return (
+
+
Client Component
+
+ This component renders client-side. The page initially delivered to the
+ client will not have FF values loaded, which can result in a
+ 'flicker' when values are loaded asynchronously client-side.
+
+
+ -
+ feature1: {feature1Enabled ? "ON" : "OFF"}
+
+ -
+ feature2: {feature2Value}
+
+
+
+ );
+}
diff --git a/next-js/src/app/client/page.tsx b/next-js/src/app/client/page.tsx
index cab5d88..a17f4d8 100644
--- a/next-js/src/app/client/page.tsx
+++ b/next-js/src/app/client/page.tsx
@@ -1,54 +1,28 @@
"use client";
-import { useEffect, useState } from "react";
+import { useEffect } from "react";
+import { GrowthBookProvider } from "@growthbook/growthbook-react";
import Cookies from "js-cookie";
-import gb from "@/lib/growthbook";
+import gb from "@/lib/growthbook/client";
+import ClientComponent from "./ClientComponent";
export default function ClientPage() {
- const [isLoading, setIsLoading] = useState(false);
-
useEffect(() => {
const load = async () => {
- await gb.loadFeatures({ timeout: 1000 });
-
- const userId = Cookies.get("gb-next-example-userId");
-
- gb.setAttributes({
- id: userId,
- });
+ try {
+ await gb.loadFeatures();
+ const userId = Cookies.get("gb-next-example-userId");
+ gb.setAttributes({
+ id: userId,
+ });
+ } catch (e) {
+ console.error(e);
+ }
};
- try {
- setIsLoading(true);
- load();
- } catch (e) {
- console.error(e);
- } finally {
- setIsLoading(false);
- }
+ load();
}, []);
-
- const feature1Enabled = gb.isOn("feature1");
- const feature2Value = gb.getFeatureValue("feature2", "fallback");
-
return (
-
-
Client Component
-
- This component renders client-side. The page initially delivered to the
- client will not have FF values loaded, which can result in a 'flicker'
- when values are loaded asynchronously client-side.
-
- {isLoading ? (
-
Loading...
- ) : (
-
- -
- feature1: {feature1Enabled ? "ON" : "OFF"}
-
- -
- feature2: {feature2Value}
-
-
- )}
-
+
Server / Client Component Combination
- This server component fetches feature flags from GB server-side, then
- passes the features object to a client-side component. The object passed
- needs to be{" "}
+ This server component fetches feature flags from GB, then passes the
+ features object to a client-side component. Since the object passed is{" "}
serializable
- {" "}
- for this to work.
+
+ , we can avoid redundantly fetching the features object client-side.
diff --git a/next-js/src/app/server/dynamic/ClientComponent.tsx b/next-js/src/app/server/dynamic/ClientComponent.tsx
index 76eb8b6..affb14d 100644
--- a/next-js/src/app/server/dynamic/ClientComponent.tsx
+++ b/next-js/src/app/server/dynamic/ClientComponent.tsx
@@ -1,7 +1,7 @@
"use client";
import { useEffect, useState } from "react";
import Cookies from "js-cookie";
-import gb from "@/lib/growthbook";
+import gb from "@/lib/growthbook/client";
export default function ClientPage() {
const [isLoading, setIsLoading] = useState(false);
diff --git a/next-js/src/app/server/dynamic/page.tsx b/next-js/src/app/server/dynamic/page.tsx
index 4a10802..f027cfe 100644
--- a/next-js/src/app/server/dynamic/page.tsx
+++ b/next-js/src/app/server/dynamic/page.tsx
@@ -1,4 +1,4 @@
-import gb from "@/lib/growthbook";
+import gb from "@/lib/growthbook/server";
import { cookies } from "next/headers";
export default async function ServerDynamic() {
diff --git a/next-js/src/app/server/static/page.tsx b/next-js/src/app/server/static/page.tsx
index 8c44bf5..67282f7 100644
--- a/next-js/src/app/server/static/page.tsx
+++ b/next-js/src/app/server/static/page.tsx
@@ -1,4 +1,4 @@
-import gb from "@/lib/growthbook";
+import gb from "@/lib/growthbook/server";
export default async function ServerStatic() {
await gb.loadFeatures({ timeout: 1000 });
gb.setAttributes({
diff --git a/next-js/src/app/server/streaming/AsyncComponent.tsx b/next-js/src/app/server/streaming/AsyncComponent.tsx
index 2a058e6..323e717 100644
--- a/next-js/src/app/server/streaming/AsyncComponent.tsx
+++ b/next-js/src/app/server/streaming/AsyncComponent.tsx
@@ -1,4 +1,4 @@
-import gb from "@/lib/growthbook";
+import gb from "@/lib/growthbook/server";
import { cookies } from "next/headers";
export default async function AsyncComponent() {
diff --git a/next-js/src/lib/growthbook/client.ts b/next-js/src/lib/growthbook/client.ts
new file mode 100644
index 0000000..a79e596
--- /dev/null
+++ b/next-js/src/lib/growthbook/client.ts
@@ -0,0 +1,11 @@
+import { GrowthBook } from "@growthbook/growthbook";
+
+const growthbook = new GrowthBook({
+ apiHost: process.env.NEXT_PUBLIC_GROWTHBOOK_API_HOST,
+ clientKey: process.env.NEXT_PUBLIC_GROWTHBOOK_CLIENT_KEY,
+ decryptionKey: process.env.NEXT_PUBLIC_GROWTHBOOK_DECRYPTION_KEY,
+ // client-side features enabled
+ subscribeToChanges: true,
+});
+
+export default growthbook;
diff --git a/next-js/src/lib/growthbook.ts b/next-js/src/lib/growthbook/server.ts
similarity index 100%
rename from next-js/src/lib/growthbook.ts
rename to next-js/src/lib/growthbook/server.ts
diff --git a/next-js/src/middleware.ts b/next-js/src/middleware.ts
index 4f939e7..6a62b06 100644
--- a/next-js/src/middleware.ts
+++ b/next-js/src/middleware.ts
@@ -1,7 +1,7 @@
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
import { cookies } from "next/headers";
-import gb from "@/lib/growthbook";
+import gb from "@/lib/growthbook/server";
export async function middleware(request: NextRequest) {
await gb.loadFeatures({ timeout: 1000 });