React-native Table 만들기

고광필·2022년 10월 17일
1

Front

목록 보기
28/33
post-custom-banner

react-native에서 표로 데이터를 보여줄 일이 생겨서 table component를 찾고 있었습니다
react-native-table-component 라이브러리를 찾아서 사용했었으나, 큰 카테고리 데이터 안에서 세부 내용을 보여줘야 했습니다

위 링크의 Example5처럼 H1이라는 큰 데이터 카테고리 안에 Title과 Title2가 있는것처럼요

이 과정에서 결국 라이브러리를 사용하지 않고 직접 개발하게 된 과정을 기록합니다

문제 상황

처음 마주한 문제는 해당 라이브러리는 큰 카테고리의 데이터 안에 세부 데이터를 넣을 때
배열 데이터가 row가 되는것이 아니라 column이 된다는겁니다

api를 통해 받는 내용이 row로 들어가야 하기 때문에 데이터의 수정이 필요합니다

두번째로는 해당 라이브러리가 개발 중단되었다는 점입니다

The project is no longer maintained due to work reasons and can be transferred if necessary.

README에서 해당 내용을 확인할 수 있습니다

방법

뭐 있겠습니까? 그냥 개발해야죠

레이아웃

react-native는 flexbox를 기본으로 사용합니다
따라서 flex로 table처럼 보이는 레이아웃을 잡아야 합니다
물론 큰 카테고리의 포함 관계를 보여주도록 해야 합니다

이런 느낌으로 잡아줍니다

전체 container가 flex-direction이 column인 flexbox입니다
첫 줄에 헤더를 넣고, 헤더는 flex-direction이 row인 flexbox로 설정합니다
두번째부터는 내용을 넣게 됩니다

내용도 flex-direction이 row인 flexbox로 설정해서
큰 카테고리와 작은 카테고리로 영역을 나눠 카테고리를 포함하는것처럼 보이게 합니다
큰 카테고리 영역은 커질 수 있어야겠고, 작은 카테고리 영역은 flex-direction이 column인 flexbox가 되어야 합니다

결과 캡처

제목이라는 큰 카테고리 안에 부제목 데이터들이 들어간것처럼 보입니다
Table 완성~

코드

// constants.js
export const heads = ['제목', '부제목', '특징', '주제', '위치'];

export const bodyDatas = [
  [
    '제목1',
    [
      ['제목1', '부제목1', '특1-1', '주1-1', '위치'],
      ['제목1', '부제목2', '특1-2', '주1-2', '위치'],
      ['제목1', '부제목3', '특1-3', '주1-3', '위치'],
    ],
  ],
  ['제목2', [['제목2', '부제목1', '특2-1', '주2-1', '위치']]],
  [
    '제목3',
    [
      ['제목3', '부제목1', '특3-1', '주3-1', '위치'],
      ['제목3', '부제목2', '특3-2', '주3-2', '위치'],
      ['제목3', '부제목3', '특3-3', '주3-3', '위치'],
      ['제목3', '부제목4', '특3-4', '주3-4', '위치'],
      ['제목3', '부제목5', '특3-5', '주3-5', '위치'],
      ['제목3', '부제목6', '특3-6', '주3-6', '위치'],
    ],
  ],
  [
    '제목4',
    [
      ['제목4', '부제목1', '특4-1', '주4-1', '위치'],
      ['제목4', '부제목2', '특4-2', '주4-2', '위치'],
      ['제목4', '부제목3', '특4-3', '주4-3', '위치'],
      ['제목4', '부제목4', '특4-4', '주4-4', '위치'],
      ['제목4', '부제목5', '특4-5', '주4-5', '위치'],
      ['제목4', '부제목6', '특4-6', '주4-6', '위치'],
    ],
  ],
];

// CustomTable.jsx
import { Entypo } from '@expo/vector-icons';
import { IconButton } from '@react-native-material/core';
import React from 'react';
import { ScrollView, StyleSheet, Text, View } from 'react-native';

import { COLOR, heads, bodyDatas } from '../../utils/constants';

const CustomTable = () => {
  return (
    <ScrollView style={styles.table}>
      <View style={[styles.row, styles.borderStyle, { backgroundColor: COLOR.MAIN_COLOR }]}>
        {heads.map((head, index) => (
          <View key={index} style={[styles.rowItem, index < 2 && { flexGrow: 1 }]}>
            <Text style={[styles.rowItemText, { color: COLOR.WHITE }]}>{head}</Text>
          </View>
        ))}
      </View>
      {bodyDatas.map(([storedName, values], index) => (
        <View key={index} style={[styles.row, styles.borderStyle]}>
          <View style={[styles.rowItem, { flexGrow: 1 }]}>
            <Text>{storedName}</Text>
          </View>
          <View style={{ flexGrow: 1 }}>
            {values.map((value, index2) => (
              <View key={index2} style={styles.row}>
                {value.map((text, index3) => {
                  if (index3 === 0 || index3 === value.length - 1) return null;

                  const style = [
                    styles.rowItem,
                    {
                      borderBottomColor: COLOR.MAIN_COLOR,
                      borderBottomWidth: index2 === values.length - 1 ? 0 : 1,
                    },
                  ];

                  return index3 ? (
                    <View style={[...style, index3 < 2 && { flexGrow: 1 }]} key={index3}>
                      <Text numberOfLines={1} ellipsizeMode="tail" style={styles.rowItemText}>
                        {text}
                      </Text>
                    </View>
                  ) : null;
                })}
              </View>
            ))}
          </View>
          <View style={[styles.rowItem]}>
            <IconButton
              icon={<Entypo name="location-pin" size={24} color={COLOR.MAIN_COLOR} />}
              style={styles.locationButton}
            />
          </View>
        </View>
      ))}
    </ScrollView>
  );
};

const styles = StyleSheet.create({
  table: { backgroundColor: COLOR.WHITE },
  row: {
    flexDirection: 'row',
    alignItems: 'center',
  },
  rowItem: {
    justifyContent: 'center',
    alignItems: 'center',
    width: 50,
    paddingVertical: 8,
    paddingHorizontal: 4,
    height: 50,
  },
  rowItemText: { textAlign: 'center' },
  borderStyle: {
    borderBottomWidth: 1,
    borderBottomColor: COLOR.BORDER_COLOR,
  },
  locationButton: {
    width: 34,
    height: 34,
  },
});

export default CustomTable;

코드에 위치 아이콘 통합 등 수정된 부분이 있습니다

정리

Table처럼 보이도록 하는 컴포넌트를 개발했습니다
해당 컴포넌트는 배열 데이터를 row로 렌더링합니다

profile
이해하는 개발자를 희망하는 고광필입니다.
post-custom-banner

1개의 댓글

comment-user-thumbnail
2023년 1월 19일

starred~

답글 달기