거의 알고리즘 일기장

React Native ( expo )를 이용한 사이드 프로젝트 만들기 -3. 공통 컴포넌트 만들기 ( header, pictureDiary ) 본문

react-native

React Native ( expo )를 이용한 사이드 프로젝트 만들기 -3. 공통 컴포넌트 만들기 ( header, pictureDiary )

건우권 2021. 12. 14. 17:58

일을 좀 쉽게 하기 위해서 공통 컴포넌트들을 만들어보자.

이 프로젝트는 작은 프로젝트라 1. header 와 2. 그림일기에 대한 컴포넌트만 만들면 될거같다.


1. header

app flow

page 별로 header를 보면, leftComponent, rightComponent만 정의해서 넣어주면 편할거 같다.

//header를 편하게 쓰기 위해서 만든 block component
import React, { ReactElement } from "react";
import { HStack, Box, StatusBar } from "native-base";
import { Colors } from "@constants";

type HeaderBlockProps = {
  leftComponent?: ReactElement;
  rightComponent?: ReactElement;
};

export const HeaderBlock = ({
  leftComponent,
  rightComponent,
}: HeaderBlockProps) => {
  return (
    <>
      <StatusBar backgroundColor={Colors.background} barStyle="light-content" />
      <Box safeAreaTop backgroundColor={Colors.background} />
      <HStack
        bg={Colors.background}
        px="1"
        py="1"
        justifyContent="space-between"
        alignItems="center"
      >
        <HStack>{leftComponent}</HStack>
        <HStack>{rightComponent}</HStack>
      </HStack>
    </>
  );
};

그리고 사용법은 간단하다.

<HeaderBlock
	leftComponent={여기다가 왼쪽에 넣을 react element}
	rightComponent={여기다가 오른쪽에 넣을 react element}
/>

2. 그림일기 컴포넌트

그림일기의 폼을 보면

1) 날짜, 날씨, 2) 제목, 3) 그림, 4) 원고지로 이루어져 있다.

1), 2), 3)번은 간단해서 세부 설명은 생략하겠다.

그림일기

4) 원고지

원고지

위처럼 script를 작성하면, 밑과 같다.

어려웠던 점은 가로세로가 동일한 비율을 가지는 반응형 박스를 만들고, 그 안의 글자를 가운데에 위치시키는 것이었다.

//MenuScriptBlock.tsx
import React, { useState } from "react";
import { Center, Text, Divider, HStack, VStack, View } from "native-base";
import { transform } from "@babel/core";

//prop으로 string값을 받음
type MenuScriptBlockProps = {
  scriptsString: string;
};

const MenuScriptBlock = ({ scriptsString }: MenuScriptBlockProps) => {

  //prop으로 받은 scriptString 값을 Array<Array<string>>의 값으로 변환
  const [scripts, setScripts] = useState(() => {
    const result = Array.from(Array<Array<string>>(5), () =>
      Array<string>(10).fill(" ")
    );

    //문자넣어주기
    for (let i = 0; i < 5; i++) {
      for (let j = 0; j < 10; j++) {
        const idx = i * 10 + j;
        if (idx < scriptsString.length) {
          result[i][j] = scriptsString[idx];
        }
      }
    }

    return result;
  });

  return (
    <VStack divider={<Divider />}>
      {/* 이건 무조건 있는값이라 !넣었음 */}
      {scripts!.map((script, idx) => (
        <HStack justifyContent="center" key={idx}>
          {script.map((word, idx) => (
     		//width, paddingBottom에 %를 주게 되면, 가로세로가 동일한 반응형 박스를 만들수 있다.
            <Center
              bg="amber.50"
              style={{
                borderWidth: 0.5,
                width: "10%",
                height: 0,
                paddingBottom: "10%",
              }}
              key={idx}
            >
              //안의 컨텐츠를 가운데에 두기 위한 css 코드
              <View
                style={{
                  position: "absolute",
                  top: 0,
                  left: 0,
                  right: 0,
                  bottom: 0,
                  justifyContent: "center",
                  alignItems: "center",
                }}
              >
                <Text>{word}</Text>
              </View>
            </Center>
          ))}
        </HStack>
      ))}
    </VStack>
  );
};

function chunkString(str: string, length: number) {
  return str.match(new RegExp(".{1," + length + "}", "g"));
}

export default MenuScriptBlock;

원고지의 전체 스크립트 (이미지 width, height 맞추는건 추후에 다시 맞출 계획임)

import React from "react";
import { Center, Container, Divider, HStack, Image, VStack } from "native-base";
import MenuScriptBlock from "@components/blocks/MenuScriptBlock";

type PictureDiaryDetailProps = {
  pictureDiary: PictureDiary;
};

const PictureDiaryDetail = ({ pictureDiary }: PictureDiaryDetailProps) => {
  return (
    <VStack>
      {/* 날짜, 날씨 */}
      <HStack divider={<Divider />}>
        <Center style={{ borderBottomWidth: 0.5 }} flex={1}>{`날짜`}</Center>
        <Center style={{ borderBottomWidth: 0.5 }} flex={3}>
          {pictureDiary.time}
        </Center>
        <Center style={{ borderBottomWidth: 0.5 }} flex={1}>{`날씨`}</Center>
        <Center style={{ borderBottomWidth: 0.5 }} flex={1}>
          {pictureDiary.weather}
        </Center>
      </HStack>

      {/* 제목 */}
      <HStack divider={<Divider width={0.5} />}>
        <Center style={{ borderBottomWidth: 0.5 }} flex={1}>{`제목`}</Center>
        <Center style={{ borderBottomWidth: 0.5 }} flex={5}>
          {pictureDiary.title}
        </Center>
      </HStack>

      {/* 이미지 */}
      <Container>
        <Image
          source={{
            uri: "https://wallpaperaccess.com/full/317501.jpg",
          }}
          alt="Alternate Text"
          size="10"
        />
      </Container>

      {/* 원고지 */}
      <MenuScriptBlock scriptsString={pictureDiary.content} />
    </VStack>
  );
};

export default PictureDiaryDetail;

이번주는 별로 개발 못함.. ㅋㅋ

 

반응형
Comments