Closed iamyoki closed 2 years ago
Hi 👋 Thank you for opening an issue.
I see you haven't declared the decorator
property in the story, have you declared it somewhere else ?
@JesusTheHun Oh! I forgot to mention that, I declared decorator
in preview.js
already.
export const decorators = [
withRouter,
(Story) => (
<SWRConfig value={{fetcher: request.get}}>
<Global styles={[rebase, layout]} />
<Story />
</SWRConfig>
),
];
Can you share a full reproduction example such as a repo ? Because I'm unable to reproduce the issue.
But just to be clear, is it normal that it is a story about PostDetail
, but that the component is named Basic
and renders PostDetailPage
?
@JesusTheHun Thank you for answering.
You are very careful, it's normal in my source actually, here I just wrote wrong.
Please check out my source code, and change this line into this
export default {
component: PostDetail,
parameters: {
reactRouter: {
routePath: '/posts/:postId',
routeParams: {postId: 1},
},
},
};
export const Basic = (args) => {
const {id} = useParams()
return <PostDetail id={id} />
};
Once you cloned and installed with yarn, use
yarn scripts
to start a storybook dev.
I've taken a look and this is not an addon issue.
You cannot use a context (here the react router context) from a story function.
If you move the useParams()
inside a component you will get the expected parameter value.
For example, this will log the param value :
const LogParam = () => {
const {postId} = useParams();
console.log(postId);
return null;
};
/** @type {import('@storybook/react').Story} */
export const Basic = (args) => {
return (
<>
<LogParam />
<PostDetail id='1' />
</>
);
};
I understand this is not what you were trying to achieve. I suggest you use a wrapper to inject the parameters :
const InjectParam = ({params, children}) => {
React.Children.only(children);
const routeParams = useParams();
const paramsToInject = {};
params.forEach((param) => {
if (typeof param === 'string') {
paramsToInject[param] = routeParams[param];
return;
}
const [routeParamName, propertyName] = param;
paramsToInject[propertyName] = routeParams[routeParamName];
});
return React.cloneElement(children, paramsToInject);
};
// Wrap your component inside your story function.
// <InjectParam params={['id']}> Using a simple string will map the `id` route param to the `id` property of the wrapper component.
// <InjectParam params={[['postId', 'id']]}> Using a tuple will map the `postId` route param to the `id` property.
// <InjectParam params={['anotherParam', ['postId', 'id']]}> You can mix both approaches
export const Basic = (args) => {
return (
<InjectParam params={[['postId', 'id']]}>
<PostDetail />
</InjectParam>
);
};
@JesusTheHun Thank you so much, it seems reasonable.
If you consider your issue resolved, please close this issue.
Reproduce
Expected
react-router's
useParams
should get the corresponding value fromrouteParams
.