210125 TIL #React

이예주·2021년 1월 25일
0

Today I Learned

목록 보기
3/10

React

웹 게임을 만들며 배우는 React(3)

module을 export하는 법

모듈을 불러와 사용하는 문법은 requireimport 두가지가 있다. 두 문법은 서로 치환이 가능하며 아래와 같이 사용된다.

const React = require('react');
import React from 'react';

모듈을 exports하면 해당 파일 또한 import가 가능한데, exports되는 게 객체나 배열이면 구조 분해가 가능하다.

/* NumberBaseball.js */
const React = require('react');
const { Component } = React;	//구조분해
class NumberBaseball {}



module.exports = NumberBaseball;

//import를 사용할 경우
export const hello = 'hello';	//import { hello }

export default NumberBaseball;	//import NumberBaseball





/* client.js */
const NumberBaseball = require('./NumberBaseball.js');	//해당 파일이 있는 경로로 들어가 불러오기
//import를 사용할 경우
import NumberBaseball from './NumberBaseball.js';

엄밀히 따지면 require는 노드의 모듈 문법(common js)이고 import는 ES6(ES2015) 문법이기 때문에 차이가 있다. 그러나 리액트 수준에서는 이 둘을 치환해서 사용해도 문제가 없다. node.js에서는 require 문법만을 지원하고 있다. 그러나 babel이 importrequire로 치환해주기 때문에 import 또한 사용이 가능하다.


react 반복문

리액트 반복문은 약간 까다롭다. 기본적으로 map() 함수를 써서 배열 안의 요소들을 불러온다. map() 함수의 callback 매개변수 v를 이용해 배열의 요소를 한개씩 꺼내오는 방식이다.

['사과', '바나나', '복숭아', '감', '배'].map((v) => {
  return (
    <li>{v}</li>
  );
})}

출력 결과

• 사과
• 바나나
• 복숭아
• 감
• 배

대개 그렇듯이 위처럼 단순한 반복문보다는 복잡한 반복문의 요소를 꺼내와야할 때가 많다.

• 사과 - 맛있다
• 바나나 - 맛없다
• 복숭아 - 달다
• 감 - 떫다
• 배 - 차다

위와 같이 요소를 두 개 이상 꺼내와야할 때는 2차원 배열을 이용하거나, 객체를 사용하면 된다.

//2차원 배열
[['사과', '맛있다'],
 ['바나나', '맛없다'],
 ['복숭아', '달다'],
 ['감', '떫다'],
 ['배', '차다']].map((v) => {
  return (
    <li>{v[0]} - {v[1]}</li>
  );
})}

//객체
[{fruit: '사과', taste: '맛있다'}, 
 {fruit: '바나나', taste: '맛없다'}, 
 {fruit: '복숭아', taste: '달다'}, 
 {fruit: '감', taste: '떫다'}, 
 {fruit: '배', taste: '차다'}].map((v) => {
  return (
    <li>{v.fruit} - {v.taste}</li>
  );
})}

map() 함수에서 두번째 callback 매개변수 i는 인덱스를 리턴한다.

['사과', '바나나', '복숭아', '감', '배'].map((v, i) =>
  <li>{v} - {i}</li>
)}

출력 결과

• 사과 - 0
• 바나나 - 1
• 복숭아 - 2
• 감 - 3
• 배 - 4

map() 함수를 사용할 때 필수적으로 따라오는 태그 요소인 key가 있다. key는 리액트가 성능 최적화를 할 때 필요로 하는 값이다. 파라미터를 사용할 태그의 속성에 key를 사용하여 배열의 고유한 값을 넣어주어야 한다.

• 사과 - 맛있다
• 바나나 - 맛없다
• 복숭아 - 달다
• 감 - 떫다
• 사과 - 차다

객체로 위 배열을 표현한다면 fruit에서 사과가 두 번 나오므로 v.fruit은 고유한 값이 될 수 없다. 위 배열에서 고유한 값을 만들어주기 위해서는 v.fruit + v.taste로 할당해주어야 한다.

<li key={v.fruit + v.taste}>{v.fruit} - {v.taste}</li>

✓주의
key에 배열의 인덱스인 i만을 할당할 수 없다. 리액트에서는 key를 기준으로 엘리먼트를 추가, 수정, 삭제 판단을 하기 때문에 배열의 순서가 바뀌면 성능 최적화에 문제가 생긴다. key 값에 i 자체를 사용하지 않는 게 좋다.


추가 팁

화살표 함수를 사용할 때 return을 사용하지 않고 소괄호만 사용하면 바로 소괄호 안의 내용이 리턴된다.

['사과', '바나나', '복숭아', '감', '배'].map((v) => (
  <li>{v}</li>
))}

['사과', '바나나', '복숭아', '감', '배'].map((v) =>
  <li>{v}</li>
)}

최적화를 위한 컴포넌트 분리

반복문이 복잡할수록, 코드가 길어질수록 코드는 최적화에서 멀어진다. 성능을 최적화하기 위해서는 반복되거나 중복 사용되는 컴포넌트는 따로 분리해주는 것이 좋다.

[{fruit: '사과', taste: '맛있다'}, 
 {fruit: '바나나', taste: '맛없다'}, 
 {fruit: '복숭아', taste: '달다'}, 
 {fruit: '감', taste: '떫다'}, 
 {fruit: '배', taste: '차다'}].map((v, i) => {
  return (
    <li>
      <b>{v.fruit}</b> - {i}
      <div>컨텐츠1</div>
      <div>컨텐츠2</div>
      <div>컨텐츠3</div>
    </li>
  );
})}

위 코드에서 HTML 부분을 Try 컴포넌트로 따로 만들어 분리해준다.

/* NumberBaseball.jsx */
[{fruit: '사과', taste: '맛있다'}, 
 {fruit: '바나나', taste: '맛없다'}, 
 {fruit: '복숭아', taste: '달다'}, 
 {fruit: '감', taste: '떫다'}, 
 {fruit: '배', taste: '차다'}].map((v, i) => {
  return (
    <Try />
  );
})}

/* Try.jsx */
<li>
  <b>{v.fruit}</b> - {i}
  <div>컨텐츠1</div>
  <div>컨텐츠2</div>
  <div>컨텐츠3</div>
</li>

이처럼 컴포넌트를 분리했을 때의 문제점은 vi를 Try 컴포넌트에서 사용할 수 없다는 것이다. 이를 위해서 따로 컴포넌트에 전달해주어야 하는데, 이때 vi를 props라고 한다.

<Try value={v} index={i} />

위와 같이 props를 넘겨주면 Try 컴포넌트에서도 해당 props를 사용할 수 있다.


✓props란?
HTML의 속성, 즉 Attribute를 리액트에서는 props라고 부른다. props가 있는 컴포넌트는 자식 컴포넌트이며, props를 전달한 컴포넌트는 부모 컴포넌트이다. 나중 가면 꽤 골치 아파지는 부분이다.

<li>
  <b>{this.props.value.fruit}</b> - {this.props.index}
  <div>컨텐츠1</div>
  <div>컨텐츠2</div>
  <div>컨텐츠3</div>
</li>

넘겨준 props는 그냥 사용할 수 없고 해당 컴포넌트에서 this.props로 불러올 수 있다.

추가 팁

jsx에서는 {/**/}를 이용해서 주석 처리를 한다. //는 사용할 수 없다.


✓화살표 함수

화살표 함수에서 =>의 생략이 가능하다. 단, =>를 생략할 경우, 함수 내부에서 this를 사용하지 못한다. this를 사용하려면 construct 함수를 따로 사용해야 한다.

class NumberBaseball extends Component {
  constructor(props) {
    super(props)
    this.state = {
      ...
    };
    this.onChangeInput = this.onChangeInput.bind(this); //onChangeInput() 사용 가능
  }
  
  onChangeInput(e) {
    this.setState({
      value: e.target.value,
    });
  };
}

bind(this)라는 해괴한 리액트 문법 때문에 화살표 함수 문법이 나온 이후에는 위 문법은 잘 사용하지 않는다.

profile
🏫Chung-Ang Univ. 👩‍💻Computer Science

0개의 댓글