React hooks can't work inside storybook for react native

Viewed 761

Technologies

  • React(17.0.2)
  • React Native(0.66.4)
  • TypeScript(4.4.4)
  • Storybook
    • @storybook/react-native(5.3.25)
    • @storybook/react-native-server(5.3.23)

What I'm facing

I'm facing the following react hook error in my Storybook.

Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.

Source code that I'm facing the error

import React, { useState } from "react";
import { Button, Text, View } from "react-native";
import { storiesOf } from "@storybook/react-native";
import CenterView from "../../../storybook/stories/CenterView";
import Modal from "react-native-modal";

storiesOf("components/modal", module)
  .addDecorator(getStory => <CenterView>{getStory()}</CenterView>)
  .add("Modal", () => {
    const [isVisible, setIsVisible] = useState<boolean>(false); // This line doesn't work
    return (
      <View>
        <Button title={"Open Modal"} onPress={() => setIsVisible(true)} />
        <Modal
          isVisible
        >
          <Text>This is modal</Text>
        </Modal>
      </View>
    );
  });

I know this line is the cause of error, but I'm not sure how to fix this.

:

const [isVisible, setIsVisible] = useState<boolean>(false); // This line doesn't work

:
1 Answers

The error is happening, because hooks cannot be called outside of a React component. I would recommend using controls to open the Modal instead, and let Storybook handle the state.

To get this working as-is, you should be able to implement a wrapper component and use that as the second argument to the story:

storiesOf("components/modal", module)
  .addDecorator(getStory => <CenterView>{getStory()}</CenterView>)
  .add("Modal", () => <StoryWrapper />);

function StoryWrapper() {
  const [isVisible, setIsVisible] = useState<boolean>(false);

  return (
    <View>
      <Button title={"Open Modal"} onPress={() => setIsVisible(true)} />
      <Modal isVisible={isVisible}>
        <Text>This is modal</Text>
      </Modal>
    </View>
  );
}
Related