[React] 리액트 입문

Yunhye Park·2023년 11월 28일
0
post-thumbnail
post-custom-banner

프로젝트가 끝나고 간만에 수업 코드를 저장한 리포에서 git pull을 받았다. 그리고 간만에 에러를 만났다.

Found a swap file by the name

  • 의미 : .swp파일(비정상적인 종료 등의 원인)이 남아있다.

요며칠 git push/pull 할 때마다 UNIX 화면으로 바뀌던 게 이때문인 것 같다.

  • 해결 :
  1. Q를 누르면 vim을 빠져나온다는데 나는 :q를 추가로 입력해야 했다.
  2. ls -al을 입력해 .swp 파일을 찾았는데, 남아있는 게 없었다.
    (있을 경우 d를 눌러 지울 수 있는 듯하다)

React.js 특징

오늘은 리액트 첫 수업이었다. 이전에 리액트 강의를 짧게 수강한 적이 있는데 실습 위주였던지라 이론을 한번 짚고 넘어가는 게 좋았다.

1. 단방향 Data Flow

오직 부모 컴포넌트에서 자식 컴포넌트로만 전달 가능하다. 자식이 부모로 보낸다거나 자식 간의 전달 또한 불가하다.
ref. angular js는 양방향 데이터 바인딩

2. Component 기반 구조

리액트는 한 페이지를 만들 때 여러 Component를 부품처럼 조립해서 만든다. 컴포넌트는 쉽게 말해 공통 부분을 묶은 일종의 함수라고 볼 수 있다. 기능/UI 단위로 캡슐화해서 재사용성 높고, 일괄 수정도 용이하다.

3. Virtual DOM

동작 원리의 핵심 중 하나가 아닐까 싶다. 기존 DOM을 복제한 가상 돔을 만들어 저장할 때마다 이전과 달라진 부분만 새로 렌더링한다. 변화가 생길 부분만 렌더링을 하기 때문에 자연히 반응 속도가 빠르다.

4. Props & State

  • props : 부모 컴포넌트 데이터 -> 자식 컴포넌트로 전달. 전달하는 쪽(부모 컴포넌트)에서만 변경이 가능하다.
  • state : 컴포넌트 내부에서 선언하는 변수. 기존 변수와 차이점이 뭔가 하니, 값을 변경한다. 원래 클래스형 컴포넌트에서만 사용 가능했으나, 리액트 16버전부터 hook이 등장하면서 함수형 컴포넌트에서도 쓸 수 있다.

5. JSX

Javascript + XML이지만, XML이 HTML과 거의 흡사하다.

Babel
리액트의 JS 코드를 HTML로 변환 & 최신 JS 문법을 이전 버전의 JS 문법으로 변환.
Webpack
코드 변경할 때마다 바로 반영해준다. 여러 파일과 모듈을 하나의 파일로 합쳐주기 때문에 리액트 프로젝트 배포에도 쓰인다.


JSX 문법

1. 하나의 태그로 감싸서 return

function FuncComponent() {
	const 

  return (
    <>
    	<div>첫번째 상자</div>
        <div>두번째 상자</div>
    </>
}

2. 변수 사용할 땐 {}

const name = 'une';
return <>
  {name}입니다.
  </>

2-1. return에 if(x), for(x), 삼항연산자!

{ 3+4 === 7 ? '정답' : '땡'}

2-2. 복잡한 조건? 함수로 만들어 사용!

JSX에서는 for문이나 if문을 직접 사용할 수 없다. 대신 JSX가 시작되기 전, 즉 return 이전에 결과값을 변수에 저장해 가져다{} 쓸 수 있다.

function FruitButton () {
  const fruit = () => {
    if(name==='peach') {
        console.log('yummy');
       }
    else if (name==='lemon') {
        console.log('Oops);
             }
    else {
        console.log('what is this?");
    }
  }

  return 
    <>
      <button onClick={fruit}>과일 버튼</button>
    </>
}

💡 2-3. 조건1이 참이어야 조건2를 읽는 &&

논리곱은 전자가 true일 때 다음으로 넘어간다. 첫 조건이 false였다면 논리곱 이후의 두번째 조건은 아예 읽지 않는다. 이점을 이용해 true 일 때만 결과를 보이게 코드를 짤 수 있다.

{ 4+5 === 9 && '정답은 9' }

조건이 거짓일 때 예외처리가 필요 없는 경우 간단하게 논리곱을 사용해도 되겠다는 걸 처음 배웠다. 처음이 true일 때만 다음 조건을 읽는다는 건 알았는데 이런 식의 응용은 생각 못해봐서 흥미로웠다!

3. inline style : style 속성값으로 객체(<-JS 문법) 전달

HTML에서 style은

<div style="font-size: red; background-color: black;"></div>

이런 식으로 따옴표 안에 나열한다. 하지만 JSX는 중괄호 안 중괄호로 처리한다. 첫번째 중괄호는 자바스크립트 코드를 사용하기 때문(2번 참조)이고, 내부에 덧댄 중괄호는 객체임을 나타낸다.

<div style={{fontSize: '20px' color: 'red'}}></div>

또한 camelCase로 작성하기 때문에 하이픈은 사용하지 않는다.

4. class와 onclick을 JSX에서는?

JSX에서 class와 onclick은 예약어라서 사용이 불가하다. 그래서 className, onClick이라 적는다.

또, html에서는 함수를 "호출"하는 부분이 필수적이었다. 선언만 하면 실행하지 않는다. 하지만 리액트에서는 함수를 "선언"하는 것으로 충분하다. 파일을 저장할 때마다 자동으로 리렌더링하기 때문에 함수를 호출하면 이벤트 발생하기 이전에 바로 실행된다. 마치 addEventListener에서 함수를 선언만 하고 실행하지 않는 것과 같은 이유다.

5. 닫는 태그 필수

6. 이미지 사용 : public or src 내부

이미지는 보통 public 폴더 안에 담는다. 슬래시로 경로를 시작하거나 이미지 자체를 import할 수도 있다.


Component & props

리액트는 컴포넌트의 집합이다. 그러니까, 한 페이지를 전체가 아닌 부분으로 나누어 필요할 때마다 가져다 쓴다. 우리가 반복되는 코드를 묶어 함수로 만들듯이 말이다. 페이지 자체를 컴포넌트로 만들기도 하고, 그렇게 만든 페이지 컴포넌트 내부 요소에 또 컴포넌트를 만들기도 한다.

card 형식이 대개 그렇다.

29CM card를 컴포넌트로 만들기

물론 29CM가 어떤 라이브러리로 개발하는지는 모르지만.. 여기서도 리액트 관점으로 컴포넌트를 짚어낼 수 있다. 내용만 바뀌지 구성과 크기는 모두 동일하다.

비슷한 뭉치를 상황에 따라 다르게 보여주려고 할 때에 새삼 리액트가 유용하겠거니 싶다. 직접 DOM 조작을 하지 않아도 알아서 변화가 있을 때마다 렌더링을 해주니 말이다.

부모 컴포넌트에서 자식 컴포넌트로 데이터를 전달할 때 대개 props를 이용한다고 했다. 함수형 컴포넌트를 생성한다면 매개변수에 props를 담는다. 개발자도구로 크기를 참고해가며 작성해봤다.

// App.js

import './App.css';
import ProductCard from './components/My29cm';

function App() {
  return (
    <div>
      <ProductCard
        brandName="유라고"
        productName="[7차 리오더] Jacquard hoodie cardigan_2colors"
        productPoster="/kuromi.jpg"
        index={0}
        Ranking=""
        originalPrice={115000}
        discountRate={10}
        currentPrice={103500}
        productLike={33931}
        productComment={88}
      />
    </div>
  );
}

export default App;
// components/ProductCard.js

function ProductCard(props) {
  return (
    <section className="product-card">
      <div className="product-card__img-body">
        <div className="product-card__img">
          <img src={props.productPoster} alt="{props.index} img" />
        </div>
        <div className="product-card__ranking">
          <span>{props.ranking}</span>
        </div>
      </div>
      <div className="product-card__info">
        <span className="product-card__brand-name">
          {props.brandName}
		</span>
        <span className="product-card__product-name">
          {props.productName}
		</span>
        <span className="product-card__original-price">
          {props.originalPrice}
        </span>
        <span className="product-card__discount-rate">
          {props.discountRate}%
        </span>
        <span className="product-card__current-price">
          {props.currentPrice}</span>
      </div>
      <div className="product-card__icon-body">
        <div className="product-card__like-body">
          <i className="heart"></i>
          <span>{props.productLike}</span>
        </div>
        <div className="product-card__comment-body">
          <i className="message"></i>
          <span>{props.productComment}</span>
        </div>
      </div>
    </section>
  );
}

export default ProductCard;

컴포넌트별 CSS 파일이 아니라서 BEM 네이밍 규칙을 생각하여 클래스명을 작성했는데 컴포넌트는 대문자로 시작한다는 점을 까먹었다.

/* App.css */
.product-card {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 0 0 40px 20px;
}

.product-card__img-body {
  position: relative;
}

.product-card__img {
  width: 250px;
  height: 250px;
}

.product-card__ranking {
  width: 40px;
  height: 40px;
  background-color: red;
  color: whitesmoke;
  position: absolute;
  bottom: 0px;
  left: 0px;
  font-weight: 600;
}

.product-card__info {
  width: 250px;
  display: flex;
  flex-direction: column;
}

.product-card__brand-name {
  text-decoration: underline;
  margin-bottom: 7px;
  font-size: 13px;
}

.product-card__product-name {
  font-size: 12px;
  height: 32px;
  padding-right: 25px;
  word-break: break-all;
}

.product-card__original-price {
  opacity: 0.2;
  font-size: 12px;
  font-family: 'Lucida Sans', sans-serif;
}

.product-card__discount-rate,
.product-card__current-price {
  color: tomato;
  font-weight: 700;
  font-size: 14px;
  font-family: 'Lucida Grande', sans-serif;
}

.product-card__icon-body {
  display: flex;
}

.product-card__like-body,
.product-card__comment-body {
  font-size: 11px;
  opacity: 0.9;
}

.product-card__like-body {
  margin-right: 50px;
}

이렇게 작성한 결과물.

처음에 이미지 파일이 안 떴다.

  • 원인 : src="{props.~~}"로 받아옴.
  • 이유 : 따옴표 안에 있어서 자바스크립트 코드(변수)로 인식하지 못함.
  • 해결 : src에 따옴표 제거!

JSX 문법은 변수와 따옴표가 공존하기 때문에 이 점을 주의해야겠다.

함수를 props로 넘길 땐

받는 쪽이 아니라 넘기는 쪽(부모 컴포넌트)에서 함수를 전달해야 한다. 간략하게 주고받는 부분만 예시로 작성해보면 이렇다.

<ProductCard function={() => {console.log('this is function')}} />
<button onClick={props.function}>함수 props</button>

오늘의 궁금증

  • 천 단위가 넘어서면 대개 쉼표를 붙여 가독성을 높인다. DB에는 숫자로 저장할 거 같은데 그럼 어디에서 쉼표 처리를 해주는 걸까?
profile
일단 해보는 편
post-custom-banner

0개의 댓글