도움말 - 글감 수집하기 (인용)

도움말 - 부분 리뷰 작성하기

리액트 죽음의 다섯 손가락. 이 다섯 가지 개념을 마스터 한 다음 리액트를 마스터하라(React’s Five Fingers of Death. Master these five concepts, then master React)

몇 년 전, 내 친구 Sean은 리액트(React)라고 불리는 이 새로운 프론트엔드 라이브러리가 어떻게 웹을 변화 시킬 것인지 얘기하기 시작했다. 처음에는 그냥 유행하는 새로운 프레임워크라고 치부했다. 하지만 나는 점점 더 리액트에 대해서 듣게 됐다. 무시하고 싶었지만 더 이상 피할 수 없었다.

어쩌면 당신은 나와 비슷 할지도 모른다. 당신은 리액트에 대해 많은 얘기를 듣고 있지만, 실제로 그것을 배우는 것은 왠지 싫을 것이다.

좋은 소식은 여기서 당신이 리액트의 5가지 키 컨셉 모두를 익힐 수 있다는 것이다.

오해하진 않았으면 좋겠다. 그렇다고 내가 당신을 당장 리액트 마스터로 만들 수 있다는 뜻은 아니다. 하지만 적어도 당신이 리액트를 배우기로 마음 먹었다면 리액트의 모든 주요 개념들을 이해 할 수 있을 것이다.

5가지 키 컨셉은 아래와 같다:

  1. 컴포넌트(Components)
  2. JSX
  3. Props & State
  4. 컴포넌트 API (The Component API)
  5. 컴포넌트 타입 (Component Types)

시작 전에, 나는 원래 Wes Bos 코스를 통해 리액트를 배웠고, 몇 개의 제휴 링크를 포함 시켰다. 또한, 무료 리소스 링크도 포함 시켰다.

오, 그리고 나의 친구 Sean? 그는 그 이후로 훨씬 더 최첨단 기술로 옮겨갔다. 어쨌든, 리액트는 2015년이 되었다.

컨셉 #1: 리액트 컴포넌트 동작 원리

리액트에 대해 알아야 할 첫 번째는 이것이 전부 컴포넌트에 대한 것이라는 거다. 당신의 리액트 코드베이스는 기본적으로 작은 컴포넌트를 호출하는 큰 컴포넌트 중 하나의 큰 더미(large pile)다.

그렇다면 컴포넌트가 무엇일까? 컴포넌트의 완벽한 예는 HTML의 <select> 엘리먼트다. 자체 시각적 출력(visual output) (엘리먼트 자체를 구성하는 회색 상자, 텍스트 라벨 및 아래쪽 화살표)이 있을 뿐만 아니라 열기(opening) 및 닫기(closing) 로직도 처리한다.



이제 나만의 방법으로(style and behavior)으로 맞춤형 <select>를 만들 수 있다고 상상해보자:



저것이 정확하게 당신이 리액트를 통해 할 수 있는 일이다. 리액트 컴포넌트는 기존 템플릿처럼 HTML을 출력 할 뿐만 아니라 해당 출력을 제어하는 데 필요한 모든 코드도 포함한 단일 객체(object)이다.

실제로 리액트 컴포넌트를 작성하는 가장 일반적인 방법은 HTML을 리턴하는 render 메서드가 포함 된 ES6 클래스다. (함수(functional) 방식이 있지만 컨셉 #4까지는 비밀이다):

class MyComponent extends React.Component {
render() {
return <p>Hello World!<p>;
}
}

컨셉 # 2 : JSX의 동작 방식

보시다시피, 컴포넌트 접근 방식은 HTML과 자바스크립트 코드가 같은 파일에 있다는 것을 의미한다. 이 위험한 동맹(unholy alliance)을 성취하기위한 리액트의 비밀 무기는 JSX 언어다 ( "X"는 "XML"을 나타냄).

JSX가 처음엔 어색해 보일 수도 있지만, 금방 익숙해 질 것이다.

우리 모두는 HTML과 자바스크립트는 철저하게 분리(separation)하라고 여태껏 배웠다. 그러나 이러한 규칙을 다소 완화한다면 실제로 프론트엔드 생산성에 놀라운 향상을 가져올 것이다

예를 들어, 자바스크립트를 최대한 활용할 수 있으므로, {...}을 사용하여 HTML에 자바 스크립트 스니핏(snippet)을 삽입하여 현재 날짜를 다음과 같이 표시할 수 있다:

class MyComponent extends React.Component {
render() {
return <p>Today is: {new Date()}</p>;
}
}

이는 또한 어떤 종류의 특정 템플릿 문법 대신 if 문이나 반복문에 일반 자바스크립트를 사용한다는 것을 의미한다. 자바스크립트의 삼항 연산자가 특히 편리하다:

class MyComponent extends React.Component {
render() {
return <p>Hello {this.props.someVar ? 'World' : 'Kitty'}</p>;
}
}

만약 최신 자바스크립트 문법에 대해 알아볼 필요가 있다면 Wes Bos의 ES6 for Everyone (영상을 원한다면) 또는 Nicolas Bevacqua의 Practical ES6(글을 원할 경우)를 추천한다.

컨셉 # 3 : Props 및 State 동작 방식

위에서 this.props.someVar 변수가 어디에서 왔는지 궁금 할 것이다.

HTML을 작성해본 적이 있다면 <a> 태그의 href와 같은 HTML 속성에 익숙 할 것이다. 리액트에서 속성은 props("properties"의 약자)로 알려져 있다. props는 컴포넌트가 서로 커뮤니케이션(talk)하는 방식이다.

class ParentComponent extends React.Component {
render() {
return <ChildComponent message="Hello World"/>;
}
}
class ChildComponent extends React.Component {
render() {
return <p>And then I said, “{this.props.message}”</p>;
}
}

이 때문에 리액트의 데이터 흐름(data flow)은 단방향이다. 데이터는 부모(parent) 컴포넌트에서 자식(children)으로만 이동할 수 있으며 다른 방향으로는 이동할 수 없다.

때로는 컴포넌트가 부모 컴포넌트에서 가져 오지 않은 데이터 (예 : 사용자 입력)를 처리(react)해야 한다. 그리고 이런 상황에서 state가 필요한 것이다.

props와 state 사이의 차이점을 이해하는 좋은 은유(metaphor)는 Etch-A-Sketch이다. Etch-A-Sketch 타블렛 (props)의 바디 컬러와 다이얼 위치와는 달리 드로잉 자체(state)는 Etch-A-Sketch의 고유 한 특성이 아니다. 사용자 입력의 일시적인 결과 일뿐이다.

사진: 전형적인 리액트 컴포넌트

컴포넌트의 state는 자식 컴포넌트에 prop으로 전달 될 수 있다는 것에 주목하자. 당신은 이것을 라우터, 데이터 레이어 및 다양한 컴포넌트가 그들만의 작은 데이터 강줄기를 구성해서 결국 메인 어플리케이션 상태를 구성하는 큰 강이라고 생각할 수 있다.


컴포넌트 내부에서 state는 setState 함수를 사용하여 관리된다. 이 함수는 종종 이벤트 핸들러 내부에서 호출된다:

class MyComponent extends React.Component {
handleClick = (e) => {
this.setState({clicked: true});
}
render() {
return <a href="#" onClick={this.handleClick}>Click me</a>;
}
}

실제 리액트 앱의 대다수 데이터는 prop이 될 것이다. 당신이 유저 입력 데이터를 처리해야 할 때만 state가 필요할 것이다.

여기서 우리는 fat arrow를 사용하여 handleClick 핸들러를 바인딩 처리한다. 이 기술에 대한 자세한 내용은 여기를 참고하자.

컨셉 #4: 컴포넌트(Component) API 동작 방식

우리는 이미 rendersetState에 대해 알아 봤다. 이 두 가지 모두 작은 컴포넌트 API 메소드 집합의 일부이다. 또 다른 유용한 방법은 state를 초기화하고 메서드를 바인딩하는 데 사용할 수 있는 생성자(constructor)이다.

이 세 가지 기능 외에도 리액트는 컴포넌트의 수명주기(lifecycle) 동안 (로드 전,로드 후, 마운트 해제 후 등) 다양한 시점에서 트리거되는 콜백 세트를 제공한다. 고급 리액트 사용자가 아니라면, 아마 이것에 대해 걱정할 필요가 거의 없을 것이다.

이 섹션이 짧은 이유는, 리액트를 배우는 것이 실제로 지루한 API 메소드를 배우는 것 보다는 프로그래밍 및 아키텍처 개념을 마스터하는 것이 훨씬 더 중요하기 때문이다. 이렇게 하면 기분이 상쾌해 질 것이다!

컨셉 #5: 컴포넌트 타입(Component Types) 동작 방식

클래스를 사용하여 컴포넌트를 정의하는 방법을 살펴 보았다:

class MyComponent extends React.Component {
render() {
return <p>Hello World!<p>;
}
}

또한 이 클래스에서 지원하는 컴포넌트 메소드에 대해서도 설명했다. 이제는 모두 잊어 버려자! 점점 더 많은 사람들이 리액트 컴포넌트를 함수형 컴포넌트로 작성하고 있다.

함수형 컴포넌트는 props 객체를 인수로 사용하여 HTML을 반환하는 함수다. 거의 전통적인 템플릿과 비슷하지만, 그 기능 내에서 필요한 자바스크립트코드를 계속 사용할 수 있다는 점이 다르다:

const myComponent = props => {
return <p>Hello {props.name}! Today is {new Date()}.</p>
}

함수형 컴포넌트 구문을 사용하면 이제 방금 설명한 컴포넌트 메소드에 액세스 할 수 없게 된다. 실제로는 완벽하게 괜찮다. 대다수의 컴포넌트에 필요하지 않을 수 있기 때문이다.

그런데 이 메소드들 중 하나는 setState이며, 이것은 함수형 컴포넌트가 상태를 가질 수 없다는 것을 의미한다. 이러한 이유로 이것은 종종 비상태 함수형 컴포넌트(statless functional component)라고 한다.

함수형 컴포넌트에는 boilerplate 코드가 훨씬 적기 때문에 가능한 경우 항상 사용하는 것이 좋다. 이러한 이유로 대부분의 리액트 앱에는 두 문법(syntax)을 혼용해서 사용된다.

createClass 함수를 사용하는 세 번째 레거시 구문도 있다. 그러나 누군가 18 개월 전(오래된) 코딩 패턴을 여전히 사용하고 있는 것은 부끄러워 해야 한다:

var Greeting = React.createClass({ 
render: function() {
return <h1>Hello, {this.props.name}</h1>;
}
});

컨셉 #6: 컴포넌트 역할(Component Roles) 동작 방식

맞다, 내가 거짓말을 했다. 실제로 다뤄야 할 것은 5 가지가 아니고 6가지이다. 하지만 영화를 "죽음의 여섯 손가락(Six Fingers of Death)"이라고 할 수는 없지 않겠는가. 지금 생각해보니, 꽤 재밌는 영화일 수 있겠다. 아마도 그 영화는 쿵푸를 마스터한 에일리언이 복수의 기회를 노리는 그런 영화가 될 것 같다.

다시 주제로 돌아가자. 다시 지루한 아키텍처 개념을 얘기해야 된다.

리액트를 어느정도 사용하고 나니, 사람들은 컴포넌트에 코드의 두 가지 별개의 "맛(flavors)"을 표현하기 시작했다. 한 가지 맛은 보여주기(showing) 및 숨기기(hiding)와 같은 UI 로직과 관련이있다. 다른 하나는 서버에서 데이터를 로드하는 것과 같은 데이터 로직에 관한 것이다.

이로 인해 컨테이너(container)프리젠테이션(presentational) 컴포넌트 ( "똑똑한(smart)"및 "멍청한(dumb)" 컴포넌트라고도 함)가 구별되었다. 컨테이너 컴포넌트는 UI가 아닌(이 부분이 중요하다) 데이터를 처리해야 한다. 프레젠테이션 컴포넌트는 그 반대이다.



즉, 전형적인(classic) 할 일 목록(to-do list) 예제에서 한 컴포넌트 데이터를 로드 한 다음 해당 데이터를 실제 HTML을 출력하고 로컬 state 변경을 처리하는 다른 컴포넌트로 전달한다.

이는 백엔드 개발자들에게 친숙한 view/controller 패턴과 매우 유사하다. ( 'member Rails?' member Django?)

컨테이너/프리젠테이션의 차이점은 Dan Abramov (Redux의 제작자)가 작성한 이 글에서 널리 알려졌고, 더 깊이 파고 싶은 경우 확인 해보는 것이 좋다.

Higher-Order 컴포넌트

글을 끝내기 전에 higher-order 컴포넌트 (종종 HoC로 단축 됨)로 알려진 컨테이너 컴포넌트 유형에 대해 조금 이야기해야한다.

HoC는 다른 컴포넌트를 감싸서 특수(special) props을 전달 할 수 있는 컴포넌트이며 일반적으로 higher-order 컴포넌트 팩토리 기능을 사용하여 작성된다. 일반적으로 사람들은 함수 자체를 "HoC"라고 부른다. 기술적으로는 100% 정확하지는 않지만 실제로 큰 문제는 아니다.

예를 들어, <MyComponent>에서 리액트 라우터(React Router)의 withRouter 팩토리 함수를 호출하면 라우트 prop을 앞서 언급 한 <MyComponent>에 전달하는 새로운 <withRouter (MyComponent) /> 컴포넌트로 래핑된다.

HoC 기능은 골프 캐디라고 생각할 수 있다. 골프 캐디는 골퍼를 따라 다니며 필요한 클럽을 골퍼에게 건네준다. 그 자체로 캐디는 실제로 골프 클럽으로는 아무 것도 할 수 없다. 골퍼에게 더 많은 도구를 제공하는 역할을 한다.


"라우터 prop을 넘겨줘, 제임스!"

HoC는 매우 강력한 개념이다. 예를 들어, Recompose 라이브러리를 사용하여 HoC를 통해 state 변경을 처리 할 수도 있다. 즉, ES6 클래스 기반 컴포넌트를 사용하지 않고 state를 관리 할 수 있다는 것이다.

HoC composition이 너무 흔해지면서 리액트가 ES6 클래스 구문에서 순수 함수 접근 방식으로 옮겨 가고있는 것처럼 보인다. 흥미롭다!

요약

우리가 방금 배운 것을 요약 해보자:

  • 리액트 코드베이스는 컴포넌트로 구성된다.
  • 이러한 컴포넌트는 JSX를 사용하여 작성된다.
  • 데이터는 컴포넌트 내부에서 발생하는 state를 제외하고 부모에서 자식으로 흐른다.
  • 컴포넌트에는 수명주기(lifecycle) 및 유틸리티 메소드의 작은 세트가 있다.
  • 컴포넌트는 순수 함수(pure functions)로 작성할 수도 있다.
  • 데이터 로직과 UI 로직은 별도의 컴포넌트로 분리해야한다.
  • higher-order 컴포넌트는 컴포넌트가 새 도구에 액세스 할 수 있게 해주는 공통 패턴이다.

믿을지 모르겠지만, 리액트 개발자가 매일 사용하는 지식의 90 %를 커버했다. 아무리 추상적이거나 모호한 패턴이라도 리액트의 가장 핵심은 항상 함수와 props다.

일단 당신이 이것을 정말로 이해하면, 리액트를 무서워하지 않을 것이다. 코드에서 패턴을 보고 새로운 코드베이스를 한눈에 이해할 수 있을 뿐 아니라 다음과 같이 자랑스럽게 얘기 할 수 있다.

"Pfff! React is so 2015!"

더 나아 가기

만약 당신이 리액트가 그렇게 나쁘지 않다는 것을 확신 할 수 있다면, 그것을 올바르게 배워고 싶을 것이다. 만약 그렇다면, React for Beginners 코스를 꼭 보기를 추천한다. 이것이 내가 리액트를 배웠던 방식이다. 실제로 functional stateless component와 같은 멋진 새로운 것들을 모두 포함한 업데이트가 되었다 :


어렵게 번 돈을 리액트를 배우는데 쓰고 싶지 않다면, 여기에 많은 리액트 리소스 목록을 확인하여 무료로 배울 수 있다.

쿨한 리액트 오픈 소스 프로젝트에 기여함으로써 이 새로 습득 한 지식을 모두 실습에 적용하고 싶다면 Telescope Nova를 확인하자. 이것은 사용자 계정, 폼 및 데이터로드가 완료된 full-stack React + GraphQL 어플리케이션을 신속하게 생성하는 가장 쉬운 방법이다. 우리가 컨트리뷰터(contributors)를 찾고 있다고 얘기했는가?



이 글은 Sacha Greif의 React’s Five Fingers of Death. Master these five concepts, then master React을 번역한 글 입니다. 원문은 아래에서 확인 할 수 있고, 잘못된 번역이 있으면 알려주시면 수정 하겠습니다. 감사합니다.



리뷰

SB Kang

리액트 죽음의 다섯 손가락. 이 다섯 가지 개념을 마스터 한 다음 리액트를 마스터하라(React’s Five Fingers of Death. Master these five concepts, then master React)

1

2