무작정 프로젝트 해보기 - 4 (RN + styled-components)

오늘처음해요·2024년 2월 21일
0

여기 어때의 홈 화면 구성만 클론 코딩하기에는 사실상 HTML/CSS만 다루고 React를 아예 안쓰는 것 같아

상세페이지, 장바구니, 결제 플로우를 구현해보기로 했다

발생한 문제
1. 해당 기능을 구현하려면 DB가 필연적인데 어떻게 할 것인가
2. 서버는 어떻게 구현할 것인가

고민하다가 Next.js(서버/라우팅이 편함, 리액트 기반) / MongoDB(JSON-BSON이라 러닝커브가 비교적 작음)를 도입하려고 했었다

문제는 프로그래머스 데브코스가 3월부터 다시 팀 프로젝트가 시작되고 + RN을 새로 배우게 되는데

해당 과정을 진행하면서 Next.js 프로젝트까지 같이 해버리면 얼마 못 가 끝날 것 같아서 차라리 RN을 각자 미리 공부해고 프로젝트를 어떻게 진행할지 결정해보려고 한다

그래서 연습 느낌으로 RN + Styled Component 조합으로 공부해볼 생각이다


첫 난관

ReactNativeReact와는 다르게 브라우저에 띄워서 작업하지 않고 Expo를 통해서 안드로이드 기반 에뮬을 띄워서 작업한다.

그러다 보니 React에서는 겪어보지 못한 많은 문제들을 만나게 되고 이왜안(이게 왜 안되지...?)의 늪에 빠지게 된다

다행히도 나보다 앞서 에러를 경험한 사람들이 문제를 해결해놔서 검색해놓으면 대부분 해결이 된다.

TypeError: Invalid character in header content ["X-React-Native-Project-Root"]

이 문제는

node_modules/@react-native-community/cli-server-api/build/statusPageMiddleware.js 파일로 가서

function statusPageMiddleware(_req, res) {
  res.setHeader('X-React-Native-Project-Root', process.cwd());
  res.end('packager-status:running');
}

process.cwd()new URL()로 감싸주면 된다

function statusPageMiddleware(_req, res) {
  res.setHeader('X-React-Native-Project-Root', new URL(process.cwd()));
  res.end('packager-status:running');
}

이렇게 바꿔주면 된다

이후

npm cache clean --force로 캐시를 비우고
리로드 한 후 npm run android를 해주면 해결된다.


두 번째 난관

계속 진도가 안나가고 여러 문제가 발생한다...
React Native는 내가 기존에 알던 리액트와 너무 다르다는 게 느껴진다

리액트에서는 5초만에 끝나는 단순한 CSS font 바꾸는 것도
한참을 찾아봤다

React Native + expo 조합으로 font 바꾸는 방법

import * as Font from 'expo-font';

async function loadFonts() {
  await Font.loadAsync({
    Pretendard: require('./assets/fonts/PretendardVariable.ttf'),
    Sokcho: require('./assets/fonts/SokchoBadaDotum.ttf'),
  });
}

export default function App() {
  loadFonts(); // 여기서 실행
  return (
    <ThemeProvider theme={theme}>
      <AppView>
        <MyText>장바구니</MyText>
        <Header />
      </AppView>
    </ThemeProvider>
  );
}

expo-font install 후에

assets/fonts 안에 폰트 파일을 넣고 불러오면 된다

styled-components 예시

const MyText = styled.Text`
  font-size: 55px;
  color: ${(props) => props.theme.colors.primary};
  background-color: ${(props) => props.theme.colors.secondary};
  font-family: Pretendard;
`;

렌더링이 끝난 후 폰트가 불러와질 수 있어서
async/await 활용해서 폰트 로딩 후 렌더링하는 방식을 사용하는 것 같다


세 번째 난관

Styled-Components에서 CSS 변수화하기

// theme.js
const theme = {
  colors: {
    primary: '#ffffff',
    secondary: '#2ecc71',
  },
};

export default theme;

변수 지정하고

import styled, { ThemeProvider } from 'styled-components';
import theme from './theme';

const MyText = styled.Text`
  font-size: 55px;
  color: ${(props) => props.theme.colors.primary};
  background-color: ${(props) => props.theme.colors.secondary};
  font-family: 'Pretendard';
`;

export default function App() {
  return (
    <ThemeProvider theme={theme}>
      <AppView>
        <MyText>ss</MyText>
      </AppView>
    </ThemeProvider>
  );
}

ThemeProvider컴포넌트로 감싸주고 프롭으로 theme를 전해주고 사용하면 된다

살짝 번거로운 것 같아서 다른 좋은 방법은 없나 찾는 중이다


네 번째 난관

RN은 svg파일을 읽지 못한다.......

해결 방법
npm install react-native-svg
npm install react-native-svg-transformer

설치 후

// './assets/icons/ArrowIcon.js'
import Svg, { Path } from 'react-native-svg';

const ArrowIcon = () => (
  <Svg
    width="24"
    height="24"
    viewBox="0 0 24 24"
    fill="none"
    xmlns="http://www.w3.org/2000/svg"
  >
    <Path
      d="M15.705 16.59L11.125 12L15.705 7.41L14.295 6L8.29498 12L14.295 18L15.705 16.59Z"
      fill="black"
    />
  </Svg>
);

export default ArrowIcon;
import ArrowIcon from '../assets/icons/ArrowIcon';

const Header = () => {
  return (
    <HeaderView>
      <ArrowIcon />
    </HeaderView>
  );
};

이런 식으로 컴포넌트화 해서 불러오면 된다

컴포넌트 별로 다른 크기로 쓰고 싶다면

import Svg, { Path } from 'react-native-svg';

const ArrowIcon = ({ width = '24', height = '24' }) => (
  <Svg
    width={width}
    height={height}
    viewBox="0 0 24 24"
    fill="none"
    xmlns="http://www.w3.org/2000/svg"
  >
    <Path
      d="M15.705 16.59L11.125 12L15.705 7.41L14.295 6L8.29498 12L14.295 18L15.705 16.59Z"
      fill="black"
    />
  </Svg>
);

export default ArrowIcon;

이런 식으로 초기화 및 동적으로 받을 수 있게 해주고

const Header = () => {
  return (
    <HeaderView>
      <ArrowIcon width="50px" height="50px" />
      <HeaderText>속초바다</HeaderText>
    </HeaderView>
  );
};

이렇게 하면 된다


10시간 30분 결과물....

난 리액트 네이티브가 밉다...

0개의 댓글