From 12ea25dfc388aa3b16b9df3b71bcc5d6038ea9df Mon Sep 17 00:00:00 2001 From: Ron Cohen Date: Fri, 11 Sep 2026 14:59:20 +0200 Subject: [PATCH] docs: correct opt-in loading, errors, and trust model --- guides/self-opt-in.md | 100 +++++++++++++++++++++--- sdk/@reflag/browser-sdk/README.md | 38 ++++++--- sdk/@reflag/browser-sdk/globals.md | 13 ++- sdk/@reflag/react-native-sdk/globals.md | 25 ++++-- sdk/@reflag/react-sdk/README.md | 74 +++++++++++++----- sdk/@reflag/react-sdk/globals.md | 31 ++++++-- sdk/@reflag/vue-sdk/README.md | 54 +++++++++++-- sdk/@reflag/vue-sdk/globals.md | 25 +++++- sdk/documents/react-sdk/README.md | 74 +++++++++++++----- 9 files changed, 346 insertions(+), 88 deletions(-) diff --git a/guides/self-opt-in.md b/guides/self-opt-in.md index 474a4f3..3ca8a6e 100644 --- a/guides/self-opt-in.md +++ b/guides/self-opt-in.md @@ -19,22 +19,36 @@ For an overview of how opt-in affects access and how memberships are managed in Render the available opt-in flags and let the current user set their opt-in status. -If you're using `` without a `` boundary, see the loading section below. +Use `@reflag/react-sdk` 1.6.2 or later. This example explicitly enables Suspense on the hook and supplies a boundary inside your existing Reflag provider. A boundary alone does not enable Suspense in the SDK. See below for loading without Suspense. ```tsx -import { useState } from "react"; +import { Suspense, useState } from "react"; import { type OptInFlag, + useClient, useOptInFlags, useSetOptIn, } from "@reflag/react-sdk"; import { Spinner } from "your-component-library"; function OptInPage() { - const { flags: optInFlags } = useOptInFlags(); + return ( + }> + + + ); +} + +function OptInList() { + const { flags: optInFlags } = useOptInFlags({ suspense: true }); if (optInFlags.length === 0) { - return

No opt-in flags are available.

; + return ( +
+

No opt-in flags to show. If you expected some, try reloading.

+ +
+ ); } return optInFlags.map((flag) => ( @@ -42,6 +56,34 @@ function OptInPage() { )); } +function ReloadOptInFlags() { + const client = useClient(); + const [isReloading, setIsReloading] = useState(false); + const [reloadError, setReloadError] = useState(null); + + async function reload() { + setReloadError(null); + setIsReloading(true); + try { + const flags = await client.refresh(); + if (!flags) throw new Error("Flag refresh failed"); + } catch { + setReloadError("Could not reload opt-in flags. Please try again."); + } finally { + setIsReloading(false); + } + } + + return ( + <> + + {reloadError &&

{reloadError}

} + + ); +} + function OptInFlagCard({ flag }: { flag: OptInFlag }) { const setOptIn = useSetOptIn(); const [isUpdating, setIsUpdating] = useState(false); @@ -57,7 +99,7 @@ function OptInFlagCard({ flag }: { flag: OptInFlag }) { optedIn: !flag.userOptedIn, }); - if (response?.ok === false) { + if (!response?.ok) { throw new Error("Opt-in request failed"); } } catch { @@ -72,6 +114,7 @@ function OptInFlagCard({ flag }: { flag: OptInFlag }) {

{flag.name}

{flag.description &&

{flag.description}

}