React Context与Storybook:如何在组件Story中修改React Context的值
很高兴能帮到你!其实通过Storybook Controls来修改React Context的值完全可行,我来分享几种实用的实现方法:
方法1:为单个Story定制Context Provider(灵活可控)
这种方法适合针对特定组件的Story单独配置Context,步骤如下:
- 先修改你的Context Provider,支持传入初始值
给SearchQueryProvider和FilterProvider添加initialValue参数,这样可以从外部控制初始状态:
// SearchQueryProvider.tsx const SearchQueryProvider = ({ children, initialValue = "" }: SearchQueryProviderProps & { initialValue?: string }) => { const [searchQuery, setSearchQuery] = useState<string>(initialValue); return ( <SearchQueryContext.Provider value={[searchQuery, setSearchQuery]}> {children} </SearchQueryContext.Provider> ); };
- 在Story中配置Controls参数并传递给Provider
在你的组件Story里定义argTypes,然后在render函数中把Controls的参数传给Provider:
// YourComponent.stories.tsx import { Meta, StoryObj } from '@storybook/react'; import { SearchQueryProvider, FilterProvider } from '../path-to-providers'; import YourComponent from '../YourComponent'; const meta = { title: 'Components/YourComponent', component: YourComponent, argTypes: { initialSearchQuery: { control: 'text', defaultValue: '', description: '初始搜索关键词', }, initialFilterValue: { control: 'text', defaultValue: '', description: '初始过滤条件', }, }, } satisfies Meta<typeof YourComponent>; export default meta; type Story = StoryObj<typeof meta>; export const Default: Story = { render: ({ initialSearchQuery, initialFilterValue }) => ( <FilterProvider initialValue={initialFilterValue}> <SearchQueryProvider initialValue={initialSearchQuery}> <YourComponent /> </SearchQueryProvider> </FilterProvider> ), };
现在你就能在Storybook的Controls面板里修改这两个参数,组件会使用对应的Context初始值渲染。
方法2:全局装饰器结合Args(统一全局控制)
如果希望所有Story都能通过全局Controls修改Context值,可以在.storybook/preview.js中结合args和argTypes实现:
// .storybook/preview.js import { FilterProvider, SearchQueryProvider } from '../path-to-providers'; export const decorators = [ (Story, { args }) => ( <FilterProvider initialValue={args.initialFilterValue}> <SearchQueryProvider initialValue={args.initialSearchQuery}> <Story /> </SearchQueryProvider> </FilterProvider> ) ]; // 定义全局默认参数 export const args = { initialSearchQuery: '', initialFilterValue: '', }; // 配置Controls类型 export const argTypes = { initialSearchQuery: { control: 'text', description: '全局初始搜索关键词', }, initialFilterValue: { control: 'text', description: '全局初始过滤条件', }, };
这样所有Story都会继承这些全局参数,你可以在Controls面板统一修改Context的初始值。
方法3:实时修改Context值(动态更新组件)
如果想要在Storybook中实时修改Context值(不仅仅是初始值),可以使用Storybook的useArgs钩子监听参数变化,然后调用Context的set方法:
// .storybook/preview.js import { useEffect, useState } from 'react'; import { useArgs } from '@storybook/react'; import { FilterContext, SearchQueryContext } from '../path-to-contexts'; export const decorators = [ (Story) => { const [args, updateArgs] = useArgs(); // 初始化Context状态 const [searchQuery, setSearchQuery] = useState(args.searchQuery); const [filterValue, setFilterValue] = useState(args.filterValue); // 当Controls参数变化时,更新Context状态 useEffect(() => { setSearchQuery(args.searchQuery); }, [args.searchQuery]); useEffect(() => { setFilterValue(args.filterValue); }, [args.filterValue]); return ( <FilterContext.Provider value={[filterValue, setFilterValue]}> <SearchQueryContext.Provider value={[searchQuery, setSearchQuery]}> <Story /> </SearchQueryContext.Provider> </FilterContext.Provider> ); } ]; export const args = { searchQuery: '', filterValue: '', }; export const argTypes = { searchQuery: { control: 'text', description: '实时修改搜索关键词', }, filterValue: { control: 'text', description: '实时修改过滤条件', }, };
现在你在Controls中输入内容时,Context的值会实时更新,依赖这些Context的组件也会立刻渲染出变化效果。
小提示
- 如果不同的Story需要独立的Context配置,优先选择方法1,避免全局配置互相干扰;
- 方法3适合需要实时预览Context变化对组件影响的场景,比如表单、筛选组件的交互测试;
- 记得给Provider的
initialValue设置合理的默认值,避免出现未定义的状态。
内容的提问来源于stack exchange,提问作者fre-ben
相关产品推荐
相关产品推荐

