Storybook: ストヌリヌ内で盎接Reactフックを䜿甚するこずはできたせん

䜜成日 2019幎02月22日  Â·  53コメント  Â·  ゜ヌス: storybookjs/storybook

バグを説明する

ストヌリヌでフックを盎接䜿甚するこずはできたせん。 Hooks can only be called inside the body of a function componentで倱敗したす。

再珟するには

コヌド䟋

import React from 'react'

import { storiesOf } from '@storybook/react'

const stories = storiesOf('Hooks test', module)

const TestComponent: React.FC = () => {
  const [state, setState] = React.useState(5)
  return (
    <button onClick={() => setState(state + 1)}>
      {state}
    </button>
  )
}

stories.add('this story works', () => <TestComponent />)

stories.add('this story fails', () => {
  const [state, setState] = React.useState(5)
  return (
    <button onClick={() => setState(state + 1)}>
      {state}
    </button>
  )
})

予想される行動
最初のストヌリヌは正垞に機胜し、2番目のストヌリヌは最初のレンダリングで倱敗したす

バヌゞョン
@storybook/[email protected]
[email protected]
[email protected]

react has workaround question / support

最も参考になるコメント

同じ問題が発生したしたが、これは回避策ずしお行う簡単なハックです。

stories.add('this story fails', () => React.createElement(() => {
  const [state, setState] = React.useState(5)
  return (
    <button onClick={() => setState(state + 1)}>
      {state}
    </button>
  )
}))

ハッキングなしでネむティブにサポヌトされた方がはるかに良いず思いたす。 メンテナも同意すれば、PRを考え出す時間を芋぀けるこずができるかもしれたせん🙂。

党おのコメント53件

これがバグかどうかはわかりたせん。 stories.addの2番目の匕数は、関数が実際のReactコンポヌネントではなく、コンポヌネントを返すこずを期埅しおいるず私は信じおいたす。 関数コンポヌネントを倖偎に移動しおみおください。ある皋床成功するはずです。

䟋

function SomeComponent() {
    const [blah] = React.useState('blah');
    return <div> {blah}</div>;
}
stories.add('BlahComponent', () => <SomeComponent />);

stories.addの2番目の匕数は、関数が実際のReactコンポヌネントではなく、コンポヌネントを返すこずを期埅しおいるず私は信じおいたす。

AFAIKはそれほど重芁ではありたせんが、垞に詊す䟡倀がありたす。 たた、 @ sargantは䜕が゚ラヌをスロヌしたすか ストヌリヌブックたたは型システム

@Keraitoいいえ、゚ラヌは正しいず確信しおいたす。

これは、reactのコンテキストから関数を呌び出しおいるためです。別名、ストヌリヌブックは次のように関数を呌び出したす。

const element = storyFn();

ない

const element = <StoryFn />

おそらく、それが機胜するように開始した堎合です。

今のずころ@gabefromutahのアドバむスは正しいです。

実際のコヌド行は次のずおりです。
https://github.com/storybooks/storybook/blob/next/app/react/src/client/preview/render.js#L24

誰かがこの䜜品を䜜るために実隓したいのなら、それが出発点だず思いたす。

@sargant @gabefromutahの提案はあなたのために働きたすか

@ndelangen @gabefromutahの提案は、私の最初の「このストヌリヌは機胜する」ずいう䟋ず同じだず思いたすか

これがバグではない堎合でも、状態にサヌドパヌティのプラグむンを䜿甚する必芁がないようにするための䟿利な拡匵機胜である可胜性がありたす。

おそらく、それが機胜するように開始した堎合です。

@ndelangenは、それが他の特定のアドオン、特に基になるレンダリングされたコンポヌネントの小道具などの情報を必芁ずするaddon-infoずどのように盞互䜜甚するかを完党には確信しおいたせん。

同じ問題が発生したしたが、これは回避策ずしお行う簡単なハックです。

stories.add('this story fails', () => React.createElement(() => {
  const [state, setState] = React.useState(5)
  return (
    <button onClick={() => setState(state + 1)}>
      {state}
    </button>
  )
}))

ハッキングなしでネむティブにサポヌトされた方がはるかに良いず思いたす。 メンテナも同意すれば、PRを考え出す時間を芋぀けるこずができるかもしれたせん🙂。

@ kevin940726それは玠晎らしいでしょう👍

私の.storybook / config.jsに以䞋を远加するずうたくいきたした

addDecorator((Story) => <Story />)

私は䌌たようなものを実装したしたが、それはたくさんのアドオン、特に小道具のドキュメントを出力するためのアドオン情報を壊すず思いたす。 私はフックを䜿甚するこずがその情報よりも重芁であるず刀断したしたずにかくそれを別々に生成するのでが、それが䞀般的なストヌリヌブックのすべおに圓おはたるずは思えたせん。 reactの倖でapiのようなフックをどのように凊理するかわかりたせん。

゜ヌスコヌドに実装しようずしたしたが、storyshot-addonで動䜜させるのに苊劎しおいたす。 すべおのスナップショットで新しい芪ノヌドが生成されるため、これは重倧な倉曎になるず思いたす。 ナヌザヌが遞択するレンダラヌを制埡できないため、1レベル深く朜るこずはできたせん。 ゜リュヌションを文曞化し、ナヌザヌがオプトむンするためのヘルパヌAPIを提䟛するなど、他の代替案を怜蚎する必芁があるず思いたす。

私の.storybook / config.jsに以䞋を远加するずうたくいきたした

addDecorator((Story) => <Story />)

@emjaksaこのスニペットを提䟛しお

これは、この問題に察する私の回避策でした。

import React, { useState } from 'react';

import { storiesOf } from '@storybook/react';
import { action } from '@storybook/addon-actions';
import { withInfo } from '@storybook/addon-info';

import SelectField from 'component-folder/SelectField';

/**
 * special wrapper that replaces the `value` and `onChange` properties to make
 * the component work hooks
 */
const SelectFieldWrapper = props => {
  const [selectValue, setValue] = useState('');

  return (
    <SelectField
      {...props}
      value={selectValue}
      onChange={e => {
        setValue(e.target.value);
        action('onChange')(e.target.value);
      }}
    />
  );
};
SelectFieldWrapper.displayName = 'SelectField';

const info = {
  text: SelectField.__docgenInfo.description,
  propTables: [SelectField],
  propTablesExclude: [SelectFieldWrapper]
};

storiesOf('Controls/SelectField', module)
  .addDecorator(withInfo)

  // ... some stories

  // this example uses a wrapper component to handle the `value` and `onChange` props, but it should
  // be interpreted as a <SelectField> component
  .add('change handler', () => 
    <SelectFieldWrapper
      id="employment-status"
      placeholder="some placeholder"
      value={//selectValue}
      onChange={e => {
          // setValue(e.target.value);
      }}
    />, { info });

私が述べたように、それでも回避策ですが、それは機胜し、 infoアドオンを壊したせん。 私は他のアドオンをテストしおいたせん

ストヌリヌデコレヌタを最埌に远加した堎合、情報アドオンは壊れたせん。

import React from 'react'

import { configure, addDecorator } from '@storybook/react'
import { withInfo } from '@storybook/addon-info'
import { withKnobs } from '@storybook/addon-knobs'

const req = require.context('../src', true, /\.stories\.js$/)

function loadStories() {
  req.keys().forEach(filename => req(filename))
}

addDecorator(
  withInfo({
    header: false,
  }),
)
addDecorator(withKnobs)
addDecorator((Story) => (
    <Story />
))

configure(loadStories, module)

さらに別の回避策

UseStateずいうナヌティリティコンポヌネントが次のように定矩されおいたす。

export const UseState = ({ render, initialValue }) => {
    const [ variable, setVariable ] = useState(initialValue)
    return render(variable, setVariable)
}

そしお、私はこのような物語でそれを䜿甚したす

.add('use state example', () => (
    <UseState
        initialValue={0}
        render={(counter, setCounter) => (            
            <button onClick={() => setCounter(counter + 1)} >Clicked {counter} times</button>
        )}
    />
)

しかし、私は@ kevin940726の回避策が䞀番奜きです

状態の倉化に぀いおストヌリヌを再レンダリングするこずができたせん。 匷制的な再レンダリングも機胜したせん。

このコヌドはReactフックにはうたく機胜したすが

storiesOf("Dropdowns", module).add("Basic", () => <DropdownBasicStory />);

@storybook/addon-infoではうたく機胜したせん
Screenshot 2019-05-13 14 35 10

これにより、この回避策は䜿甚できなくなりたす。 䜕か案は ストヌリヌブック5.1.0-beta.0

@artyomtrityak addon-infoのpropTablesオプションを䞊曞きできたすか 今埌のaddon-docsこれを適切に解決したす https 

@shilmanには、 <DropdownBasicStory />゜ヌスも含たれたすか

@artyomtrityak私に䜕ができるか芋おいきたす😆

皆さんこんにちは 最近、この問題はあたり進んでいないようです。 それでも質問、コメント、バグがある堎合は、遠慮なく議論を続けおください。 残念ながら、すべおの問題に取り組む時間はありたせん。 私たちはい぀でも寄付を受け付けおいたすので、サポヌトが必芁な堎合はプルリク゚ストを送信しおください。 非アクティブな問題は30日埌にクロヌズされたす。 ありがずう

他の誰かがただこれを取埗しおいる堎合、問題は機胜コンポヌネントに小道具タむプを远加しおいるようです。

const Dropdown = () => (
  // component content
);

Dropdown.propTypes = {
  ...
}

䜕らかの理由で.propTypesコメントアりトするず、うたくいくようです。 ドキュメントの解析などの小道具の皮類に問題があるかどうかはわかりたせん。

フック付きのコンポヌネントの゜ヌスコヌドを衚瀺するには

function WithState({ children }) {
  const [value, setValue] = React.useState([]);

  return React.cloneElement(children, {
    value,
    onChange: event => setValue(event.target.value),
  });
}

storiesOf(`${__dirname}`, module).add('Basic', () => (
  <WithState>
    <select value="[parent state]" onChange="[parent func]">
      <option value="Australia">Australia</option>
      <option value="Cambodia">Cambodia</option>
    </select>
  </WithState>
));

皆さんこんにちは 最近、この問題はあたり進んでいないようです。 それでも質問、コメント、バグがある堎合は、遠慮なく議論を続けおください。 残念ながら、すべおの問題に取り組む時間はありたせん。 私たちはい぀でも寄付を受け付けおいたすので、サポヌトが必芁な堎合はプルリク゚ストを送信しおください。 非アクティブな問題は30日埌にクロヌズされたす。 ありがずう

䞊蚘のReact.createElementず<Story />アプロヌチには泚意しおください。実際には、reactコンポヌネントストヌリヌコンポヌネントを返すのではなく、再䜜成しおいるため、正しくない堎合もあるず思いたす。レンダリングされた芁玠ドキュメントに瀺されおいるように、ストヌリヌブックconfig.js story()を䜿甚しおいる間。

たずえば、ストヌリヌにコンポヌネントのロヌカル状態の曎新をトリガヌするKnobs.buttonある堎合、ボタンをクリックした埌、珟圚のコンポヌネントの状態を曎新する代わりに、新しいストヌリヌコンポヌネントを䜜成しおいる可胜性がありたす。

この単玔なコヌドスニペットで私の仮定を確認できたす。このスニペットでは、ノブボタンをクリックしおも倀は曎新されたせん。

storiesOf('Test', module).add('with text', () => {
  return React.createElement(() => {
    const [value, setValue] = React.useState(1);

    Knobs.button('Increase', () => setValue(prev => prev + 1));

    return <span>{value}</span>;
  });
});

それを機胜させるには、次のこずができたす。

function MyStory() {
  const [value, setValue] = React.useState(1);

  Knobs.button('Increase', () => setValue(prev => prev + 1));

  return <span>{value}</span>;
}

storiesOf('Test', module).add('with text', () => <MyStory />);

したがっお、回避策ずしお、ラッパヌを䜜成したした。

import {
  DecoratorParameters,
  Story,
  StoryDecorator,
  storiesOf as origStoriesOf,
} from '@storybook/react';

class ReactStory {
  private readonly story: Story;

  constructor(name: string, module: NodeModule) {
    this.story = origStoriesOf(name, module);
  }

  public add(
    storyName: string,
    Component: React.ComponentType,
    parameters?: DecoratorParameters
  ): this {
    this.story.add(storyName, () => <Component />, parameters);
    return this;
  }

  public addDecorator(decorator: StoryDecorator): this {
    this.story.addDecorator(decorator);
    return this;
  }

  public addParameters(parameters: DecoratorParameters): this {
    this.story.addParameters(parameters);
    return this;
  }
}

new ReactStory('Test', module).add('with text', () => {
  const [value, setValue] = React.useState(1);

  Knobs.button('Increase', () => setValue(prev => prev + 1));

  return <span>{value}</span>;
});

オプションで、ストヌリヌブックAPIを暡倣しおリファクタリングのオヌバヌヘッドを削枛し、問題が修正された埌で元に戻すこずができたす。

export function storiesOf(name: string, module: NodeModule) {
  return new ReactStory(name, module);
}

私は間違っおいるかもしれたせん、もしそうなら、私に知らせおください。 倧倉感謝いたしたす

タダ!! この問題を参照するPR7571を含むhttps://github.com/storybookjs/storybook/releases/tag/v5.2.0-beta.10をリリヌスしたした。 今すぐアップグレヌドしおお詊しください

このプレリリヌスは@next NPMタグにありたす。

この問題を閉じたす。 ただただやるこずがあるず思われる堎合は、再床開いおください。

@shilmanありがずう 䜿甚方法のコヌドスニペットの䟋はありたすか

@shilmanありがずうございたす
しかし、それでも゚ラヌが発生したす
React Hook "useState"は、React関数コンポヌネントでもカスタムReactHook関数でもない関数 "component"で呌び出されたす。

@shiranZe最近の5.2ベヌタ版を䜿甚しおいたすか

@shilmanはい...

stories / components / Menu / index.jsの私のコヌド

constコンポヌネント==> {
const [buttonEl、setButtonEl] = useStatenull

const handleClick = (event) => {
    console.log('the event', event)
    setButtonEl(event.currentTarget)
}

return (
    <>
        <IconButton iconName={"menu-hamburger"} size="s" onClick={handleClick} color={"midGray"}></IconButton>

デフォルトの゚クスポヌト[readme、component];

およびstories / components / index.js内
storiesOf('Components', module) .addDecorator(withKnobs) .add('Text', withReadme(...Menu))

@shiranZe addon-readmeの問題だず思いたす-倚分そこに問題を提出したすか

返信ありがずうございたす@shilman 。 それが問題かどうかはわかりたせん。 addon-readmeなしで詊したしたが、同じ゚ラヌが発生したす。 5.2ベヌタ版のストヌリヌブックのURLはありたすか
https://storybooks-official.netlify.com/ その他|デモ/ボタンを芋おみたした
しかし、reactフックの䟋は芋぀かりたせん。

5.2.0-beta.30にはただ問題がありたすが、ノブアドオンも䜿甚しおいるため、回避策が機胜しおいたせん。

@shiranZe私たちのnetlifyデプロむはオフになっおいたすcc @ndelangenが、 nextブランチのリポゞトリをチェックしおそこで詊すこずができたす。

@sourcesoftノブに関連する「プレビュヌフック」の問題cc @Hypnosphiは、この問題ずは䜕の関係もないず思いたす。共通しおいるのはフックの抂念だけです。

@shilmanありがずう、私はあなたが正しいず思いたす。 ずころで、詊行錯誀で修正する方法を芋぀け、カスタムフックを倉曎したした。

export const useField = (id, updateField) => {
  const onChange = useCallback((event) => {
    const {
      target: { value },
    } = e;
    updateField(id, value);
  };

  return {
    onChange,
  };
}, []);

に

export const useField = (id, updateField) => {
  const onChange = (event) => {
    const {
      target: { value },
    } = e;
    updateField(id, value);
  };

  return {
    onChange,
  };
};

基本的に、ここでuseCallbackの䜿甚を削陀したした。 最初のバヌゞョンが有効なフックであったかどうかはわかりたせんが、以前は機胜しおいたした。 たた、゚ラヌがHooks can only be called inside the body of a function component堎合や、Reactの耇数のバヌゞョンがある堎合は、少し混乱したす。

䞊蚘の䟋では、 useCallback削陀した埌、実際にuseFieldフックを登録するこず

ノブ付きのフックの䜿甚に問題があるようです。 誰かが簡単な再珟を提䟛できるなら、私はそれを芋お喜んでいたす

@shilman以前に投皿した䟋を詊したしたか スニペットは次のずおりです。

storiesOf('Test', module).add('with text', () => {
  return React.createElement(() => {
    const [value, setValue] = React.useState(1);

    Knobs.button('Increase', () => setValue(prev => prev + 1));

    return <span>{value}</span>;
  });
});

叀いAPIを䜿甚しおいたすが、テスト甚に最新のAPIに簡単に倉換できるはずです。 元の投皿から予想される動䜜を芋぀けるこずができたす。

@zhenwenc参考たでに、コヌドは機胜したすが、 react-docgen-typescript-webpack-pluginによっおレンダリングされたドキュメントの䜿甚を䞭断したす。

回避策は少し脆匱で、他のラむブラリず競合しおいるようです。 別の方法ずしお、誰かが䜿甚した経隓がありたすか https 

ここで゚ラヌメッセヌゞをグヌグルで怜玢しおいる人のために

クラスコンポヌネントをフック付きの機胜コンポヌネントに倉曎し、 useStateが@storybook/addonsから誀っおむンポヌトされたずきに、この゚ラヌが発生したした。 私はから来お、それを必芁ずreactではなく@storybook/addons自動むンポヌトが倱敗したす...。

@orpheusのスニペットのリク゚ストに答えるだけです

私の.storybook / config.jsに以䞋を远加するずうたくいきたした
addDecorator((Story) => <Story />)

@emjaksaこのスニペットを提䟛しお

diff --git a/.storybook/config.js b/.storybook/config.js
--- a/.storybook/config.js
+++ b/.storybook/config.js
@@ -1,6 +1,9 @@
-import { configure } from '@storybook/react';
+import { configure, addDecorator } from '@storybook/react';
+import React from 'react';

 // automatically import all files ending in *.stories.js
 configure(require.context('../stories', true, /\.stories\.js$/), module);
+
+addDecorator((Story) => <Story />);

結果完党な.storybook/config.js 

import { configure, addDecorator } from '@storybook/react';
import React from 'react';

// automatically import all files ending in *.stories.js
configure(require.context('../stories', true, /\.stories\.js$/), module);

addDecorator((Story) => <Story />);

これがストヌリヌブック内でreactフックを機胜させるための最良の方法かどうかはわかりたせんが、ストヌリヌブックを独自のコンポヌネントでラップする<Story />コンポヌネントはここで"@storybook/react": "^5.2.6", 。

これを行う前に、ノブ぀たり、ブヌル倀を曎新するたびに、最初のレンダリングで機胜したしたが、その埌レンダリングを停止したした。 䞊蚘の解決策はそれを修正したした。 ずころで、ストヌリヌブックで反応フックを䜿甚するのが良い習慣かどうかはわかりたせん。可胜であればすべおをモックするだけです。おそらくこの方法の方が良いでしょう。

バグを説明する

ストヌリヌでフックを盎接䜿甚するこずはできたせん。 Hooks can only be called inside the body of a function componentで倱敗したす。

再珟するには

コヌド䟋

import React from 'react'

import { storiesOf } from '@storybook/react'

const stories = storiesOf('Hooks test', module)

const TestComponent: React.FC = () => {
  const [state, setState] = React.useState(5)
  return (
    <button onClick={() => setState(state + 1)}>
      {state}
    </button>
  )
}

stories.add('this story works', () => <TestComponent />)

stories.add('this story fails', () => {
  const [state, setState] = React.useState(5)
  return (
    <button onClick={() => setState(state + 1)}>
      {state}
    </button>
  )
})

予想される行動
最初のストヌリヌは正垞に機胜し、2番目のストヌリヌは最初のレンダリングで倱敗したす

バヌゞョン
@storybook/[email protected]
[email protected]
[email protected]

======================================

矢印機胜を䜿甚しお機胜コンポヌネントを䜜成しないでください。
以䞋の䟋の1぀ずしお実行したす。

function MyComponent(props) {
  const [states, setStates] = React.useState({ value: '' });

  return (
    <input
      type="text"
      value={states.value}
      onChange={(event) => setStates({ value: event.target.value })}
    />
  );
}

たたは

//IMPORTANT: Repeat the function name

const MyComponent = function MyComponent(props) { 
  const [states, setStates] = React.useState({ value: '' });

  return (
    <input
      type="text"
      value={states.value}
      onChange={(event) => setStates({ value: event.target.value })}
    />
  );
};

「ref」おそらくルヌプ内に問題がある堎合、解決策はforwardRefを䜿甚するこずです。

// IMPORTANT: Repeat the function name
// Add the "ref" argument to the function, in case you need to use it.

const MyComponent = React.forwardRef( function MyComponent(props, ref) {
  const [states, setStates] = React.useState({ value: '' });

  return (
    <input
      type="text"
      value={states.value}
      onChange={(event) => setStates({ value: event.target.value })}
    />
  );
});

これはMDXでどのように達成できたすか

しかし、それでも゚ラヌが発生したす
React Hook "useState"は、React関数コンポヌネントでもカスタムReactHook関数でもない関数 "component"で呌び出されたす。
https://github.com/storybookjs/storybook/issues/5721#issuecomment -518225880

私はこれずたったく同じ問題を抱えおいたした。 修正は、名前付きストヌリヌの゚クスポヌトを倧文字にするこずです。

 'react'からReactをむンポヌトしたす。
 './Foo'からFooをむンポヌトしたす。

デフォルトの゚クスポヌト{
 タむトル 'Foo';
 };

 export const Basic ==> <Foo />

ドキュメントには時䟡総額が掚奚されるず曞かれおいたすが、その譊告を消したい堎合は必芁です。

私の堎合、問題は、䜿甚しおいたフックをむンポヌトするのを忘れたこずでした。

私の.storybook / config.jsに以䞋を远加するずうたくいきたした

addDecorator((Story) => <Story />)

@emjaksaありがずう Storybook v5.3でテストされ、正垞に動䜜しおいたす。

同じ問題が発生したした。機胜的なreactコンポヌネントにuseState(value)あり、 valueがKnobsから新しい倀を再レンダリングしたせん

Reactドキュメントから
Screen Shot 2020-08-07 at 19 00 04

実甚的な゜リュヌションStorybookv5.3

Preview.jsを曎新したす

.storybook/preview.js
import React from 'react'; // Important to render the story
import { withKnobs } from '@storybook/addon-knobs';
import { addDecorator } from '@storybook/react';

addDecorator(withKnobs);
addDecorator(Story => <Story />); // This guy will re-render the story

たた、main.jsを曎新したす

.storybook/main.js
module.exports = {
  stories: ['../src/**/*.stories.jsx'],
  addons: [
    '@storybook/preset-create-react-app',
    '@storybook/addon-knobs/register', // Attention to this guy
    '@storybook/addon-actions',
    '@storybook/addon-links',
  ],
  webpackFinal: async config => {
    return config;
  },
};


❓
この呌び出しデコレヌタがフックを機胜させる理由を誰かが知っおいたすか

`` `tsx
SomeComponent.decorators = [Story=> ]

@tmikeschuこれは、 <Story />がフックに必芁なReact.createElementでコヌドをラップしおいるためです。

@shilmanありがずうございたす

このペヌゞは圹に立ちたしたか
0 / 5 - 0 評䟡