javascript - 你如何用 react-router 布局路由来包装故事?

标签 javascript reactjs react-router storybook

我有一个非常简单明了的 ComponentX,它可以呈现一些样式化的 HTML,不需要数据获取甚至路由。它有一个简单的故事。 ComponentX 旨在用于深色主题网站,因此它假定它将继承 color: white;和其他这样的风格。这对于正确渲染 ComponentX 至关重要。我不会让您厌烦 ComponentX 的代码。

那些上下文样式,比如background-color: black;color: white; , 适用于 <body>通过 GlobalStyles成分。 GlobalStyles使用 css-in-js 库 Emotion将样式应用于文档。

import { Global } from '@emotion/react';

export const GlobalStyles = () => (
  <>
    <Global styles={{ body: { backgroundColor: 'black' } }} />
    <Outlet />
  </>
);

如您所见,该组件不接受子组件,而是用作布局路由,因此它呈现一个 <Outlet />。 .我希望应用程序使用 (1) 指示的布局路由来呈现如下所示的路由树。

  <Router>
    <Routes>
      <Route element={<GlobalStyles/>} >      <== (1)
        <Route path="login">
          <Route index element={<Login />} />
          <Route path="multifactor" element={<Mfa />} />
        </Route>

未显示:<Login><Mfa>页面调用 ComponentX。

这有效!

问题出在故事上。如果我用 ComponentX 渲染一个普通的故事,它将很难被看到,因为它需要所有这些样式在 <body> 上。在场。显而易见的解决方案是创建一个装饰器,用这个 <Route element={<GlobalStyles/>} > 包装每个故事.如何做到这一点?这是我的工作但不是预期的组件-x.stories.tsx:

import React from 'react';

import ComponentX from './ComponentX';

export default {
  component: ComponentX,
  title: 'Component X',
};

const Template = args => <ComponentX {...args} />;

export const Default = Template.bind({});
Default.args = {};
Default.decorators = [
  (story) => <div style={{ padding: '3rem' }}>{story()}</div>
];

(我意识到我可以使 <GlobalStyles> 成为整个 <Router> 的简单包装器组件,但我想使用此模式为采用其他中间布局路线的其他组件创建故事。)

最佳答案

我通常做的是创建自定义装饰器组件来处理包装需要提供给它们的特定“上下文”的故事。

示例用法:

创建故事装饰器函数

import React from 'react';
import { Story } from '@storybook/react';
import { ThemeProvider } from '@mui/material/styles';
import CssBaseline from '@mui/material/CssBaseline';
import { MemoryRouter as Router, Routes, Route } from 'react-router-dom';
import theme from '../src/constants/theme';
import { AppLayout } from '../src/components/layout';

// Provides global theme and resets/normalizes browser CSS
export const ThemeDecorator = (Story: Story) => (
  <ThemeProvider theme={theme}>
    <CssBaseline />
    <Story />
  </ThemeProvider>
);

// Render a story into a routing context inside a UI layout
export const AppScreen = (Story: Story) => (
  <Router>
    <Routes>
      <Route element={<AppLayout />}>
        <Route path="/*" element={<Story />} />
      </Route>
    </Routes>
  </Router>
);

.storybook/preview.js

import { INITIAL_VIEWPORTS } from '@storybook/addon-viewport';
import { ThemeDecorator } from './decorators';

export const parameters = {
  actions: { argTypesRegex: '^on[A-Z].*' },
  controls: {
    matchers: {
      color: /(background|color)$/i,
      date: /Date$/,
    },
  },
  options: {
    storySort: {
      includeName: true,
      method: 'alphabetical',
      order: ['Example', 'Theme', 'Components', 'Pages', '*'],
    },
  },
  viewport: {
    viewports: {
      ...INITIAL_VIEWPORTS,
    },
  },
};

export const decorators = [ThemeDecorator]; // <-- provide theme/CSS always

任何需要应用布局和路由上下文的故事:

import React from 'react';
import { ComponentStory, ComponentMeta } from '@storybook/react';
import { AppScreen, MarginPageLayout } from '../../.storybook/decorators';

import BaseComponentX from './ComponentX';

export default {
  title: 'Components/Component X',
  component: BaseComponentX,
  decorators: [AppScreen], // <-- apply additional decorators
  parameters: {
    layout: 'fullscreen',
  },
} as ComponentMeta<typeof BaseComponentX>;

const BaseComponentXTemplate: ComponentStory<typeof BaseComponentX> = () => (
  <BaseComponentX />
);

export const ComponentX = BaseComponentXTemplate.bind({});

在我的示例中,您可以想象将 所有 您的提供程序和 Global 组件(w/props)放置在我作为 ThemeDecorator 实现的内容中> 并设置为所有故事的默认装饰器。

关于javascript - 你如何用 react-router 布局路由来包装故事?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74722305/

相关文章:

javascript - 出现错误 404 后,我的流停止在 RxJs 中工作

javascript - 本例中如何正确使用useState?

javascript - create-react-app with node express 获取 %PUBLIC_URL%

reactjs - JavaScript 和 JSX 有什么区别?

javascript - 如何将 jQuery AJAX 调用返回的值分配给类变量?

javascript - 在react-router中创建动态链接列表

javascript - 使用Reactjs Router Switch进行导航时如何在网页之间传递变量

javascript - 如何在 Hapi.js 的预处理程序中抛出错误

javascript - 检查数组中的每个项目在 JavaScript 中是否相同

javascript - 语音服务 Azure - 服务器连接失败