[react-csv] ReactJS에서 원하는 형식대로 CSV 파일 export하기

어드민에서 유저 정보와 게시글 정보를 한 개의 CSV 파일로 export하여 다운로드 가능하게 해야했다.

react-csvreact-query를 활용하여 다운로드 버튼 클릭시 CSV 파일이 지정한 형식대로 생성되어 다운로드하는 방식으로 하였다.

 

react-csv

Build CSV files on the fly basing on Array/literal object of data

www.npmjs.com

DownloadButton.tsx를 아래와 같이 함수형 컴포넌트로 구성하였다.

export const DownloadButton = () => {
    const { data: users } = useQuery<User[]>('/admin/users', fetcher); // admin api에서 유저 정보를 가져옵니다.
    const { data: stories } = useQuery<Story[]>('/admin/stories', fetcher); // admin api에서 게시물 정보를 가져옵니다.
  // CSVLink는 react-csv에서 import
    return (
    	<>
            <CSVLink>
            	<Button text="다운로드"/>
            </CSVLink>
        </>
    ); 
};

CSVLink는 data={ } props에 csvData와 같이 2차원 배열를 전달해야 작동한다.

Admin API에서 리턴해온 users 정보와 stories를 활용하여 2차원 배열을 구성한다.

csvData = [ [ 어떤 정보인지 알려주는 row ],[ 칼럼 이름의 모음 ], 관련된 데이터 값 ]; 의 형식으로 작성하였다.

export const DownloadButton = () => {
    const { data: users } = useQuery<User[]>('/admin/users', fetcher); // admin api에서 유저 정보를 가져옵니다.
    const { data: stories } = useQuery<Story[]>('/admin/stories', fetcher); // admin api에서 게시물 정보를 가져옵니다.
  // CSVLink는 react-csv에서 import
  
    const csvData: Array<Object[]> = [
        ['1. 유저 정보'], // 유저 정보임을 알리는 row를 추가합니다.
        [ // 유저 정보의 칼럼 이름을 입력합니다.
        'Id',
        '닉네임',
        '이메일',
        '휴대폰번호',
        '성별',
        '지역',
        '나이',
        '인스타그램 아이디',
        '회원가입일',
        '마케팅동의',
        '관리자메모',
    	],
        ...(users?.items?.map((user: User) => { // Row에 채울 값들을 map으로 하나씩 분리하여 Column 별로 넣습니다.
        const { // user 정보를 각각 칼럼에 맞춰넣습니다.
          id,
          username,
          email,
          phoneNumber,
          gender,
          region,
          age,
          instarId,
          createdAt,
          marketingAgree,
          adminMemo,
         } = user;
        return [
          id,
          username,
          email,
          phoneNumber,
          gender,
          region,
          age,
          instarId,
          createdAt,
          marketingAgree,
          adminMemo,
        ];
     }) || []),
    ['2. 게시글관리'], // 게시글 정보임을 알리는 row를 추가합니다.
    [
      'Id', // 게시글 정보의 칼럼 이름을 입력합니다.
      '닉네임',
      '이메일',
      '휴대폰번호',
      '성별',
      '지역',
      '나이',
      '등록일시',
      '게시글제목',
      '좋아요 수',
      '메인소개동의',
      '마케팅동의',
    ],
    ...(stories?.items?.map((story: Story) => {
      const { id, createdAt, title, likeAmount, chatAmount } = story;
      const { // 게시물 정보 값을 각각 칼럼 이름에 맞춰 넣습니다. 
        username,
        email,
        phoneNumber,
        gender,
        region,
        age,
        marketingAgree,
      } = story.user;
      return [
        id,
        username,
        email,
        phoneNumber,
        gender,
        region,
        age,
        createdAt,
        title,
        likeAmount,
        chatAmount,
        marketingAgree,
      ];
    }) || []),
    ];
    
    return (
    	<>
            <CSVLink data={csvData}>
            	<Button text="다운로드"/>
            </CSVLink>
        </>
    ); 
};

 

코드 예시

export const DownloadButton = () => {
  const { data: users } = useQuery<User[]>(`/admin/users`, fetcher);
  const { data: stories } = useQuery<Story[]>('/admin/stories', fetcher);

  const csvData: Object[] = [
    ['1. 유저 정보'],
    [
      'Id',
      '닉네임',
      '이메일',
      '휴대폰번호',
      '성별',
      '지역',
      '나이',
      '인스타그램 아이디',
      '회원가입일',
      '마케팅동의',
      '관리자메모',
    ],
    ...(users?.items?.map((u: User) => {
      const {
        id,
        username,
        email,
        phoneNumber,
        gender,
        region,
        age,
        instarId,
        createdAt,
        marketingAgree,
        adminMemo,
      } = u;
      return [
        id,
        username,
        email,
        phoneNumber,
        gender,
        region,
        age,
        instarId,
        createdAt,
        marketingAgree,
        adminMemo,
      ];
    }) || []),
    ['2. 게시글관리'],
    [
      'Id',
      '닉네임',
      '이메일',
      '휴대폰번호',
      '성별',
      '지역',
      '나이',
      '등록일시',
      '게시글제목',
      '좋아요 수',
      '메인소개동의',
      '마케팅동의',
    ],
    ...(stories?.items?.map((s: Story) => {
      const { id, createdAt, title, likeAmount, chatAmount } = s;
      const {
        username,
        email,
        phoneNumber,
        gender,
        region,
        age,
        marketingAgree,
      } = s.user;
      return [
        id,
        username,
        email,
        phoneNumber,
        gender,
        region,
        age,
        createdAt,
        title,
        likeAmount,
        chatAmount,
        marketingAgree,
      ];
    }) || []),
  ];
  return (
    <>
      <CSVLink data={csvData}>
        <Button text="다운로드" />
      </CSVLink>
    </>
  );
};

결과

다음과 같이 csv 파일이 export된다.