Storybook에 React Navigation 환경 셋업해주기

FeRo 페로·2024년 7월 18일
0

React Navigation을 도입해서 각 Screen 컴포넌트를 이어주고, type도 지정을 해주니까 Storybook 빌드에서 에러가 발생하면서 실행이 되지 않았다. 그래서 찾아보니, Navigation에 대한 환경을 설정해주지 않아서 그런 것이었다.

그런데 스토리북 컴포넌트 안에서 useNavigation과 useRoute 훅을 사용해서 해당 컴포넌트가 필요로 하는 navgation, route를 전달해 주었는데도 이런 에러가 발생한 것이었다.

기본적으로 Navigation은 부모 Screen 컴포넌트로부터 필요한 props를 받기 때문에 이렇게 useNavigation으로는 해결되지 않는다.

기존 Storybook의 preview.tsx는 다음과 같았다.

import React from 'react';
import type { Preview } from '@storybook/react';
import { ThemeContextProvider } from '../src/context/theme';
import { INITIAL_VIEWPORTS } from '@storybook/addon-viewport';
import { QueryClientProvider, QueryCache, QueryClient } from 'react-query';
import { ReactQueryDevtools } from 'react-query/devtools';

const queryClient = new QueryClient();

const preview: Preview = {
  parameters: {
    actions: { argTypesRegex: '^on[A-Z].*' },
    controls: {
      matchers: {
        color: /(background|color)$/i,
        date: /Date$/,
      },
    },
    viewport: {
      viewports: INITIAL_VIEWPORTS,
      defaultViewport: 'iphone6',
    },
  },
  decorators: [
    (Story, context) => {
      return (
        <QueryClientProvider client={queryClient}>
          <ThemeContextProvider>
            <style>
              {`html, body, #storybook-root {
              height: 100%;`}
            </style>
            <Story {...context} />
            <ReactQueryDevtools />
          </ThemeContextProvider>
        </QueryClientProvider>
      );
    },
  ],
};

export default preview;

데코레이터 프로퍼티를 보면 어떤 스토리북 문서든지 동일한 처리를 해주는 것으로 되어있다. 여기서 네비게이션 컨텍스트 설정을 해주기로 했다. 일단 환경이 될 부모 Screen 컴포넌트를 먼저 만들어 주었다.

import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';

const StoryBookStack = createStackNavigator();

export const NavigationDecorator = ({
  Story,
  context,
}: {
  Story: (param: any) => JSX.Element;
  context: any;
}) => {
  const Renderer = () => <Story {...context} />;
  return (
    <NavigationContainer independent={true}>
      <StoryBookStack.Navigator>
        <StoryBookStack.Screen
          component={Renderer}
          name='MyStorybookScreen'
          options={{ header: () => null }}
        />
      </StoryBookStack.Navigator>
    </NavigationContainer>
  );
};

이렇게 만든 네비게이션 데코레이터 컴포넌트로 preview.tsx에 적용해 보았다. 물론 모든 스토리북 문서에 이 데코레이터 컴포넌트를 적용할 수 있겠지만, atom, molecule과 같이 네비게이션이 적용되지 않는 하위 레이어에서는 굳이 네비게이션 데코레이터를 적용할 필요가 없다는 생각이 들어서 분기처리를 하기로 했다.

console을 찍어보다 보니 context에서 문서의 경로를 얻을 수 있었다. 그래서 screens 파일에 있는 문서들에 한해서만 네비게이션 데코레이터 컴포넌트를 적용하였다.

import React from 'react';
import { type Preview } from '@storybook/react';
import { ThemeContextProvider } from '../src/context/theme';
import { INITIAL_VIEWPORTS } from '@storybook/addon-viewport';
import { QueryClientProvider, QueryClient } from 'react-query';
import { NavigationDecorator } from './NavigationDecorator';

const queryClient = new QueryClient();

const preview: Preview = {
  parameters: {
    actions: { argTypesRegex: '^on[A-Z].*' },
    controls: {
      matchers: {
        color: /(background|color)$/i,
        date: /Date$/,
      },
    },
    viewport: {
      viewports: INITIAL_VIEWPORTS,
      defaultViewport: 'iphone6',
    },
  },
  decorators: [
    (Story, context) => {
      const fileName = context.parameters.fileName;
      const isScreen = fileName.includes('screens');

      if (isScreen) {
        return (
          <QueryClientProvider client={queryClient}>
            <ThemeContextProvider>
              <style>
                {`html, body, #storybook-root {
            height: 100%; #storybook-root > div {
                height: 100%;
              }}`}
              </style>
              <NavigationDecorator story={Story} />
            </ThemeContextProvider>
          </QueryClientProvider>
        );
      }
      return (
        <QueryClientProvider client={queryClient}>
          <ThemeContextProvider>
            <style>
              {`html, body, #storybook-root {
          height: 100%; }`}
            </style>
            <Story {...context} />
          </ThemeContextProvider>
        </QueryClientProvider>
      );
    },
  ],
};

export default preview;

프로젝트가 좀 커지다 보니까, 각각 atom, molecule에 대한 스토리북 문서가 작업에 거의 필수였다. 새로운 컴포넌트 작업을 해야 하는데, 잘 돌아가던 스토리북 문서가 먹통이 되는 바람에 어떤 atom과 molecule을 어떤 attributes를 설정해서 사용해야 하는지 확인할 방법이 직접 하나씩 해보는 것 말고는 없었다. 그래서 시작한 디버깅이었는데 잘 처리되어서 다행이다.

<참고>
React Navigation 5 and Storybook

profile
주먹펴고 일어서서 코딩해

0개의 댓글