From 919eac2dde4ecab675937d7bb7ee5505ca0c7009 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 25 Feb 2026 15:10:58 +0000
Subject: [PATCH 1/3] Initial plan
From 0c5405ee4e5100d94d27db2721b7c9b8e255f9e1 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 25 Feb 2026 15:26:45 +0000
Subject: [PATCH 2/3] Improve hooks error message and add documentation about
mixing Storybook and React hooks
Co-authored-by: valentinpalkovic <5889929+valentinpalkovic@users.noreply.github.com>
---
.../src/preview-api/modules/addons/hooks.ts | 5 +++-
docs/writing-stories/args.mdx | 24 +++++++++++++++++++
docs/writing-stories/decorators.mdx | 2 +-
3 files changed, 29 insertions(+), 2 deletions(-)
diff --git a/code/core/src/preview-api/modules/addons/hooks.ts b/code/core/src/preview-api/modules/addons/hooks.ts
index b0c2edaf2c9c..34ff7c2257d7 100644
--- a/code/core/src/preview-api/modules/addons/hooks.ts
+++ b/code/core/src/preview-api/modules/addons/hooks.ts
@@ -218,7 +218,10 @@ const areDepsEqual = (deps: any[], nextDeps: any[]) =>
deps.length === nextDeps.length && deps.every((dep, i) => dep === nextDeps[i]);
const invalidHooksError = () =>
- new Error('Storybook preview hooks can only be called inside decorators and story functions.');
+ new Error(
+ 'Storybook preview hooks can only be called inside decorators and story functions.\n\n' +
+ "When combining Storybook hooks (e.g. useArgs) with framework hooks (e.g. React's useState, useEffect, useRef) in the same render function, use Storybook's equivalents from 'storybook/preview-api' instead: useState, useEffect, useRef, useMemo, useCallback, useReducer."
+ );
function getHooksContextOrNull<
TRenderer extends Renderer,
diff --git a/docs/writing-stories/args.mdx b/docs/writing-stories/args.mdx
index 1a69d5c2c35a..9800df918658 100644
--- a/docs/writing-stories/args.mdx
+++ b/docs/writing-stories/args.mdx
@@ -145,6 +145,30 @@ Args specified through the URL will extend and override any default values of ar
{/* prettier-ignore-end */}
+
+
+ When using Storybook hooks (e.g., `useArgs`) in a render function, **do not** mix them with framework hooks like React's `useState`, `useEffect`, or `useRef`. React re-renders triggered by state updates (e.g., from `useState`'s setter) do not run through Storybook's hook context, which causes a `Storybook preview hooks can only be called inside decorators and story functions` error on re-render.
+
+ Instead, use Storybook's equivalents from `storybook/preview-api`: `useState`, `useEffect`, `useRef`, `useMemo`, `useCallback`, and `useReducer`. These are designed to work correctly alongside Storybook hooks like `useArgs`.
+
+ ```tsx
+ // ✅ Correct: import all hooks from storybook/preview-api
+ import { useArgs, useState, useEffect } from 'storybook/preview-api';
+
+ export const MyStory = {
+ render: function Render(args) {
+ const [{ value }, updateArgs] = useArgs();
+ const [localState, setLocalState] = useState(false);
+
+ useEffect(() => {
+ // side effects here
+ }, [value]);
+
+ return ;
+ },
+ };
+ ```
+
## Mapping to complex arg values
diff --git a/docs/writing-stories/decorators.mdx b/docs/writing-stories/decorators.mdx
index 7acaf6bdfa33..2a31268544d9 100644
--- a/docs/writing-stories/decorators.mdx
+++ b/docs/writing-stories/decorators.mdx
@@ -62,7 +62,7 @@ The second argument to a decorator function is the **story context** which conta
* `args` - the story arguments. You can use some [`args`](./args.mdx) in your decorators and drop them in the story implementation itself.
* `argTypes`- Storybook's [argTypes](../api/arg-types.mdx) allow you to customize and fine-tune your stories [`args`](./args.mdx).
* `globals` - Storybook-wide [globals](../essentials/toolbars-and-globals.mdx#globals). In particular you can use the [toolbars feature](../essentials/toolbars-and-globals.mdx#global-types-and-the-toolbar-annotation) to allow you to change these values using Storybook’s UI.
-* `hooks` - Storybook's API hooks (e.g., useArgs).
+* `hooks` - Storybook's API hooks (e.g., `useArgs`, `useGlobals`). These are available in both decorators and story render functions. When using these hooks in a render function alongside framework hooks (e.g., React's `useState`, `useEffect`), use Storybook's hook equivalents from `storybook/preview-api` instead to avoid errors on re-render.
* `parameters`- the story's static metadata, most commonly used to control Storybook's behavior of features and addons.
* `viewMode`- Storybook's current active window (e.g., canvas, docs).
From 4bf2e5bb7f7a0518fac41af78f09eb6691fd2d0a Mon Sep 17 00:00:00 2001
From: jonniebigodes
Date: Fri, 27 Feb 2026 14:45:46 +0000
Subject: [PATCH 3/3] Adjust warning callout on args
---
docs/writing-stories/args.mdx | 22 ++--------------------
1 file changed, 2 insertions(+), 20 deletions(-)
diff --git a/docs/writing-stories/args.mdx b/docs/writing-stories/args.mdx
index 9800df918658..fa70545cdb38 100644
--- a/docs/writing-stories/args.mdx
+++ b/docs/writing-stories/args.mdx
@@ -147,27 +147,9 @@ Args specified through the URL will extend and override any default values of ar
{/* prettier-ignore-end */}
- When using Storybook hooks (e.g., `useArgs`) in a render function, **do not** mix them with framework hooks like React's `useState`, `useEffect`, or `useRef`. React re-renders triggered by state updates (e.g., from `useState`'s setter) do not run through Storybook's hook context, which causes a `Storybook preview hooks can only be called inside decorators and story functions` error on re-render.
- Instead, use Storybook's equivalents from `storybook/preview-api`: `useState`, `useEffect`, `useRef`, `useMemo`, `useCallback`, and `useReducer`. These are designed to work correctly alongside Storybook hooks like `useArgs`.
-
- ```tsx
- // ✅ Correct: import all hooks from storybook/preview-api
- import { useArgs, useState, useEffect } from 'storybook/preview-api';
-
- export const MyStory = {
- render: function Render(args) {
- const [{ value }, updateArgs] = useArgs();
- const [localState, setLocalState] = useState(false);
-
- useEffect(() => {
- // side effects here
- }, [value]);
-
- return ;
- },
- };
- ```
+ If you're using Storybook's hooks API in the story's render function, **do not** mix them with React's hooks such as `useState`, `useEffect`, or `useRef`. This is because side effects and re-rendering triggered by React's hooks do not run through Storybook's hook context, which can cause an error on re-render. To manage state and side effects within a story, you must use Storybook's equivalent hooks, such as `useState`, `useEffect`, and `useRef` from `storybook/preview-api`.
+