엘리먼트 중첩
계층적 방식으로 더 복잡한 구조를 만드는 방법은 엘리먼트를 중첩하는 것이다.
<div>또는<span>을 컨테이너로 사용하는 것이 일반적으로 좋은 선택이다.

createElement()에 전달하는 매개변수의 수는 제한이 없다. 두 번째 매개변수 이후의 모든 매개변수는 자식 엘리먼트가 된다. React 개발자 도구에서 확인해보면 두 엘리먼트가 같은 계층에 위치한다.
- 문자열로 작성한 일반적인 HTML태그, 예를 들면 'h1', 'div', 'p'처럼 화살괄호가 없는 문자열이다. 이름은 소문자로 작성한다.
- React 컴포넌트 클래스 객체. HelloWorld를 예로 들 수 있다. React 컴포넌트 클래스의 이름은 대문자로 시작한다.
React는 표준 HTML 요소를 탐색해서 일치하는 것이 있으면 해당 React 엘리먼트의 유형으로 사용한다. 예를 들어 'p'를 넘겼다면 p는 문단태그이므로 이에 일치하는 것을 찾을 수 있다. 이렇게 해서 React 엘리먼트를 렌더링하면 DOM에 <p>가 생성된다.
React 컴포넌트 클래스 생성
React 엘리먼트를 중첩하고 나면, 곧 입력할 엘리먼트가 굉장히 많다는, 다음 문제를 발견하게 될 것이다.
컴포넌트 클래스(component class) 를 이용하면 기능을 느슨하게 결합된 부분으로 분리하여 코드를 재사용할 수 있다. 컴포넌트 클래스는 컴포넌트(component) 라고 부르기도 한다.(웹 컴포넌트와 혼동하지 않아야 한다.)
표준 HTML 태그를 블록이라고 가정할때. React 컴포넌트 클래스를 구성하는데, 이 블록들을 사용해서 클래스의 인스턴스인 사용자 정의 엘리먼트를 생성할 수 있다. 사용자 정의 엘리먼트를 이용하면 이식 가능한 클래스(구성할 수 있고, 재사용할 수 있는 컴포넌트)에 논리를 추상화하고 캡슐화할 수 있다. 이런 추상화는 여러 팀이 거대하고 복잡한 애플리케이션에 UI를 재사용하는 것은 물론이고, 다른 프로젝트에서도 재사용할 수 있게 해준다. 자동완성 컴포넌트, 도구상자, 메뉴 등을 예로 들 수 있다.
ReactDOM.render() -> HelloWorld! -> div -> h1 & h1
ES6 문법을 이용하면 React.Component 클래스를 상속받아서 React 컴포넌트 클래스를 생성할 수 있다. class CHILD extends PARENT 같은 형식으로 작성한다.
새로운 컴포넌트 클래스를 구현할 때는 render() 메서드를 반드시 작성해야 한다. 이 메서드는 다른 사용자 정의 컴포넌트 클래스나 HTML 태그로 만든 React 엘리먼트를 반환해야 한다. 엘리먼트를 중첩하는 것도 가능하다.
규칙에 따라 React 컴포넌트를 담는 변수의 이름은 대문자로 시작한다. JSX 없이 자바스크립트만 사용하는 경우에는 이런 규칙을 따르지 않아도 된다.(helloWorld 처럼 소문자 변수명을 사용할 ㅅ구 있다.) 그렇지만 JSX를 사용할 경우에는 이 규칙을 따라야 하므로 여기서부터 이 규칙을 적용할 것을 추천한다. (JSX에서 React는 일반 <h1> 같은 HTML 요소와> 같은 사용자 정의 컴포넌트를 대소문자로 구분한다. 반면에, 자바스크립트만 사용하는 경우에는 'h1' 이나 HelloWorld처럼 전달하는 변수에 따라 구분한다.
ES6+/ES2015+와 React
render() 메서드를 ES6 문법으로 정의한다. 콜론(:)과 function 키워드를 입력하지 않았다. 이것은 함수를 값으로 하는 속성(키 또는 객체 프로퍼티)을 선언하는 것과 동일하다. 즉 render:function()을 작성하는 것과 같다. ES6의 메서드 작성법을 사용하는 것은 내가 선호하기도 하고, 추천하고 싶은 방법이기도 하다. 왜냐하면 이 방법이 코드가 더 짧고, 짧게 작성할수록 실수할 가능성도 줄어들기 때문이다.
React.createClass()를 사용하는 것과 ES6 클래스를 사용해서 React.Component를 상속받는 것에는 약간 차이가 있다. 일반적으로 둘 중에 한 가지 방법을 택하는 것이 좋고, 둘을 동시에 사용하는 것은 추천하지 않는다. React 버전 15.5.4이후부터 createClass() 메서드는 지원종료(deprecated) 되었다.
ES6 주요기능에 대한 자세한 정보가 필요하다면, 악셀 라우슈마이어(Axel Rauschmayer)의 저서 확인하기
ES6 탐색하기도 추천한다. 인터넷에 무료로 공개되어 있기도 하다.
ReactDOM.render()와 유사하게, 컴포넌트 클래스의 render() 메서드는 엘리먼트 하나만 반환한다. 여러 개의 동일 계층 엘리먼트를 반환하려면, <div>나 <span> 요소처럼 스타일에 영향을 주지 않는 엘리먼트로 감싸야 한다.
ECMAScript6 호환성 표 : https://kangax.github.io/compat-table/es6
render() 반환값 :
https://reactjs.org/blog/2017/09/26/react-v16.0.html#new-render-return-types-fragments-and-strings
https://reactjs.org/docs/react-component.html#render
컴포넌트가 제공하는 라이프사이클(lifecycle) 이벤트, 상태(state), DOM 이벤트 등 여러 가지 기능을 활용하면 독립적이면서도 애플리케이션의 다른 영역과 함께 잘 동작하는 컴포넌트를 만들 수 있다.
React 속성 사용하기
React 컴포넌트의 속성(properries)은 React 선언형 스타일의 기초라고 할 수 있다. 속성은 엘리먼트내의 변경할 수 없는 값이라고 생각하자. 속성을 통해 React 엘리먼트가 다양한 모습을 가질 수 있다.
다음 예제 코드는 속성에 새로운 값을 전달하면 링크 URL을 변경할 수 있다.
React.createElement('a', {href: 'http://node.university'})
속성은 컴포넌트 내부에서는 변경할 수 없는 값이라는 점을 기억하자. 부모 컴포넌트는 자식의 생성 시점에 속성을 할당한다. 자식 엘리먼트에서 속성을 수정하지 않아야 한다. (여기서 말하는 자식 엘리먼트는 다른 엘리먼트의 안에 중첩된 엘리먼트를 말한다.)
다음 예제 코드는 속성명(PROPERTY_NAME)에 값(VALUE)을 입력하는 방식으로 속성을 전달할 수 있다.
<TAG_NAME PROPERTY_NAME=VALUE/>
React의 속성은 HTML 속성을 작성하는 것과 비슷하다. React 속성을 작성하는 목적은 HTML 속성을 작성하는 것도 있지만, 다른 목적도 있다. 엘리먼트의 속성을 코드에서 원하는 대로 사용하는 것도 가능하다. 속성은 다음과 같은 용도로 쓸 수 있다.
- 일반적인 HTML 요소의 속성:href, title, style, class 등
- React 컴포넌트 클래스의 자바스크립트 코드에서 this.props의 값. 예를 들어 this.props. PROPERTY_NAME(PROPERTY_NAME을 임의의 값으로 정할 수 있음)
첫 번째 경우로, 일치하는 HTML 속성이 있으면 해당 엘리먼트의 HTML 속성으로 사용한다. 입력한 속성의 이름이 PROPERTY_NAME이라면 컴포넌트 클래스 코드에서는 this.props.PROPERTY_NAME으로 접근할 수도 있다.
두 번째 경우로, 표준 HTML 속성명과 일치하지 않는다면 속성명이 표준 속성이 아닌 것이다. 이 때는 HTML에 렌더링하지 않는다. 그렇지만 이 값은 this.props 객체에서 this.props.PROPERTY_NAME 같은 방식으로 접근할 수 있다. render() 메서드에서 입력하여 렌더링하거나 코드에서 활용할 수 있다. 이 방법을 이용하면 같은 클래스의 서로 다른 인스턴스에 각각 다른 데이터를 넘겨줄 수 있다. 이렇게 컴포넌트를 재사용할 수 있는데, 엘리먼트마다 다른 속성을 제공해서 서로 다르게 렌더링하도록 프로그래밍 방식으로 변경할 수 있기 때문이다.
- id:HTML 표준 속성 id와 일치하고, React가 자동으로 렌더링한다.
- fremeworkName:<h1>의 표준 속성이 아니지만, 제목 텍스트로 표시할 때 사용하는 값이다.
- title:HTML 표준 속성인 titlee과 일치하고, React가 자동으로 렌더링한다.
<div> 컨테이너 내부에 HelloWorld 엘리먼트를 생성하는 시점에 createEelement()의 두번째 인자로 객체 리터럴로 속성을 작성하여 넘겨준다.
ReactDOM.render(
React.createElement(
'div',
null,
React.createElement(HelloWorld, {
id: 'ember',
frameworkName: 'Ember.js',
title: 'A framework for creating ambitious web applications.'}),
React.createElement(HelloWorld, {
id: 'backbone',
frameworkName: 'Backbone.js',
title: 'Backbone.js gives structure to web applications...'}),
React.createElement(HelloWorld, {
id: 'angular',
frameworkName: 'Angular.js',
title: 'Superheroic JavaScript MVW Framework'}),
),
document.getElementById('content')
)
컴포넌트의 render() 메서드 내에서 this.props 객체에 접근하면 createElement()의 두 번쨰 매개변수로 전달한 객체에 전달할 수 있다. 예를 들면 {id: 'ember'...}와 같은 객체다. 다음은 frameworkName으로 넘긴 값에 접근할 수 있다.
render() 메서드에서 frameworkName 속성 사용하기
Class HelloWorld extends React.Component{
render() {
return React.createElement(
'hi',
null,
'Hello ' + this.props.frameworkName + ' world!!!'-------세 문자열을 합친다.
)
}
}
this.props 객체의 키는 createElement()의 두 번째 매개변수로 전달한 객체의 키와 같다. this.props의 키로 id. frameworkName, title을 확인할 수 있다. React.createElement()의 두 번째 인자로 전달하는 키-값 쌍의 수는 제한이 없다. 컴포넌트로 인스턴스를 생성하는 개발자가 스타일 속성을 직접 입력할 수 있도록 ㅎ ㅐ야 할 떄 따라서 렌더링할 HTML 속성에 제한을 두지 않아야 한다.
HelloWorld 컴포넌트의 모든 속성을 <h1>으로 전달하는 경우
Class HelloWorld extends React.Component{
render() {
return React.createElement(
'hi',
this.props, ------- 모든 속성을 자식 엘리먼트에 전달한다.
'Hello ' + this.props.frameworkName + ' world!!!'
)
}
}
엘리먼트를 컨테이너 <div>에 렌더링할 때
엘리먼트 생성 시 속성 전달
Class HelloWorld extends React.Component{
render() {
return React.createElement(
'hi',
this.props,-------HeelloWorld 컴포넌트로 전달한 모든 속성을 createElement를 호출할 때 <h1> 엘리먼트로 전달한다.
'Hello ' + this.props.frameworkName + ' world!!!'------- frameworkName 속성은 <h1>의 텍스트로 노출한다.
)
}
}
ReactDOM.render(
React.createElement(
'div',
null,
React.createElement(HelloWorld, {
'div'
null,
React.createElement(HelloWorld, {
id: 'ember',
frameworkName: 'Ember.js',
title: 'A framework for creating ambitious web applications.'}),
React.createElement(HelloWorld, {
id: 'backbone',
frameworkName: 'Backbone.js',
title: 'Backbone.js gives structure to web applications...'}),
React.createElement(HelloWorld, {
id: 'angular',
frameworkName: 'Angular.js',
title: 'Superheroic JavaScript MVW Framework'}),
),
document.getElementById('content')
)
마치며
지금까지는 대부분 이론적인 내용이라 지루할 수 있지만, 리액트로 개발할때 있어서 상태라는 개념과, 재사용성 등의 특징등은 꼭 필요한 필수개념이기에 꼭 제대로 짚고 가야하는 부분이라 생각된다.
- 리액트 엘리먼트를 중첩하여 자식엘리먼트로 추가하려면 createElement()의 세번째 인자로 계속해서 전달하면 된다.
- 리액트 엘리먼트를 생성할때 사용자 정의 컴포넌트를 사용한다.
- 속성을 사용하여 리액트 엘리먼트의 렌더링 결과를 바꾼다.
- 부모 컴포넌트는 자식엘리먼트에 속성을 전달할 수도 있다.
- React 컴포넌트를 통해 컴포넌트 기반 아키텍쳐를 구현할 수 있다.
- class NAME extends React.Component를 사용한다. 이 외에는 ReferenceError가 발생하고 실패한다.
- React 컴포넌트 클래스에서는 render() 메서드만 필수사항이다. 이외에는 선택적으로 적용할 수 있다.
- 속성은 this.props 객체를 통해서 접근할 수 있다.
- 속성을 변경하는 것은 불가능하다.
- 재사용 가능한 UI를 만들기 위해서 컴포넌트를 사용한다.
'도서 > 리액트 교과서' 카테고리의 다른 글
| React- 리액트 교과서 5장 React 컴포넌트 라이프사이클 이벤트 (0) | 2021.08.31 |
|---|---|
| React- 리액트 교과서 4장 React 컴포넌트의 상태 객체 (0) | 2021.08.31 |
| React- 리액트 교과서 3장 JSX (0) | 2021.08.23 |
| React 란 무엇인가. (0) | 2021.08.07 |