Search code examples
reactjstypescriptnext.jsstorybook

Can't map component prop


I am passing props to my component that link to storybook. Problem is object that i pass in is don't map. and it says

"TypeError: data.map is not a function".

So i think my object is not an "array" yet and i tried fix until code look like this.

Works.mocks.ts

import { ImgixImage } from '@/model/storage';
import { IWorks } from './Works';

const base: IWorks = [
  {
    projectID: 1,
    projectName: 'Project - 1',
    projectPic: { url: ImgixImage.main_portfolio1, width: 360, height: 480 },
    projectDesc:
      'Project - 1 || Photo booth fam kinfolk cold-pressed sriracha leggings jianbing microdosing tousled waistcoat.',
  },
  {
    projectID: 2,
    projectName: 'Project - 2',
    projectPic: { url: ImgixImage.main_portfolio2, width: 360, height: 480 },
    projectDesc:
      'Project - 2 || Photo booth fam kinfolk cold-pressed sriracha leggings jianbing microdosing tousled waistcoat.',
  },
  {
    projectID: 3,
    projectName: 'Project - 3',
    projectPic: {
      url: 'https://dummyimage.com/720x400',
      width: 360,
      height: 480,
    },
    projectDesc:
      'Project - 3 || Photo booth fam kinfolk cold-pressed sriracha leggings jianbing microdosing tousled waistcoat.',
  },
];

export const mockWorksProps = {
  base,
};

Works.tsx

import Image from 'next/image';

interface project {
  projectID: number;
  projectName: string;
  projectPic: { url: string; width: number; height: number };
  projectDesc: string;
}

export interface IWorks extends Array<project> {}

const Works: React.FC<IWorks> = (works: IWorks) => {
  const data = works;
  return (
    <div className="">
      <div className="">
        <div className="">
          {data.map(({ projectID, projectName, projectPic, projectDesc }) => (
            <div key={projectID} className="">
              <div className="">
                <Image
                  className=""
                  src={projectPic.url}
                  width={projectPic.width}
                  height={projectPic.height}
                  alt="https://dummyimage.com/360x480"
                />
              </div>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
};

export default Works;

Works.stories.tsx

import { ComponentMeta, ComponentStory } from '@storybook/react';
import Works, { IWorks } from './Works';
import { mockWorksProps } from './Works.mocks';

export default {
  title: 'templates/Works',
  component: Works,
  argTypes: {},
} as ComponentMeta<typeof Works>;

const Template: ComponentStory<typeof Works> = (args) => <Works {...args} />;

export const Base = Template.bind({});

Base.args = {
  ...mockWorksProps.base,
} as IWorks;

What is need to fix prop as an "array" ? Help of any kind is much appreciated


Solution

  • React components take a props object as an argument, not direct prop value. In Works you've named the entire props object works. works should instead be a property of the props object.

    interface project {
      projectID: number;
      projectName: string;
      projectPic: { url: string; width: number; height: number };
      projectDesc: string;
    }
    
    export interface IWorks {
      works: Array<project>;
    }
    
    const Works: React.FC<IWorks> = ({ works }: IWorks) => {
      return (
        <div className="">
          <div className="">
            <div className="">
              {works.map(({ projectID, projectName, projectPic, projectDesc }) => (
                <div key={projectID} className="">
                  <div className="">
                    <Image
                      className=""
                      src={projectPic.url}
                      width={projectPic.width}
                      height={projectPic.height}
                      alt="https://dummyimage.com/360x480"
                    />
                  </div>
                </div>
              ))}
            </div>
          </div>
        </div>
      );
    };
    

    ...

    import { ComponentMeta, ComponentStory } from '@storybook/react';
    import Works, { IWorks } from './Works';
    import { mockWorksProps } from './Works.mocks';
    
    export default {
      title: 'templates/Works',
      component: Works,
      argTypes: {},
    } as ComponentMeta<typeof Works>;
    
    const Template: ComponentStory<typeof Works> = (args) => <Works {...args} />;
    
    export const Base = Template.bind({});
    
    Base.args = {
      works: mockWorksProps.base, // <-- pass a works prop
    } as IWorks;