-
[React] 주요 개념 정리React 2019. 4. 24. 15:58반응형
React 주요 개념 정리
- 다음은 리액트 공식 사이트(https://reactjs.org/)의 Docs 를 읽고 요약 정리한 내용입니다.
Hello World
가장 단순한 React 예시
아래 코드는 페이지에 "Hello, world!"라는 제목을 보여준다.
ReactDOM.render( <h1> Hello, world! </h1>, document.getElementById('root') );
최신 자바스크립트 문법
- let and const 문을 사용하여 변수를 정의한다.
- class 키워드를 사용하여 JavaScript 클래스를 정의한다. 객체와 달리 클래스 메소드 사이에 쉼표를 넣을 필요가 없다. 클래스가 있는 다른 많은 언어와 달리 JavaScript에서는 this 메소드의 값이 호출되는 방식에 따라 다르다.
- 때때로 "화살표 함수" =>를 정의 하기 위해 사용한다.
JSX 소개
아래 변수 선언을 살펴보자.
const element = <h1> Hello, world! </h1>;
위에 희한한 태그 문법은 문자열도, HTML도 아닌 JSX 라 JavaScript를 확장한 문법이다.
React와 함께 사용할 것을 권장함
JSX는 React 엘리먼트(element)를 생성한다.
JSX란?
- React는 별도의 파일에 마크업과 로직을 넣어 기술을 인위적으로 분리하는 대신, 둘 다 포함하는 "컴포넌트"라고 부르는 느슨하게 연결된 유닛으로 관심사를 분리한다.
JSX에 표현식 포함하기
아래 코드에서는 name이라는 변수를 선언한 후 중괄호로 감싸 JSX안에 사용하였다.
const name = 'spring'; const element = <h1> Hello, {name} </h1>; ReactDOM.render( element, document.getElementById('root') );
JSX의 중괄호 안에는 유효한 모든 JavaScript 표현식을 넣을 수 있다. 예를 들어 2 + 2, user.firstName 또는 formatName(user) 등은 모두 유효한 JavaScript 표현식이다.
JSX도 표현식이다
- JSX를 if 구문 및 for loop 안에 사용하고, 변수에 할당하고, 인자로서 받아들이고, 함수로부터 반환할 수 있다.
JSX 속성 정의
속성에 따옴표를 이용해 문자열 리터럴을 정의할 수 있다.
const element = <div tabIndex = "0"></div>
중괄호를 사용하여 어트리뷰트에 JavaScript 표현식을 삽입할 수도 있음
const element = <img src = {user.avatarUrl}</img>;
JSX는 HTML 보다는 Javascript에 가깝기 때문에 camelCase 프로퍼티 명명 규칙을 사용한다.
태그가 비어있다면 XML처럼 />를 이용해 바로 닫아주어야 한다.
JSX 태그는 자식을 포함할 수 있다.
JSX는 주입 공격을 방지한다.
JSX는 객체를 표현한다.
React 엘리먼트
Babel 은 JSX를 react.createElement() 호출로 컴파일한다.
React.createElement()는 버그가 없는 코드를 작성하는데 도움이 되도록 몇 가지 검사를 수행하며, 기본적으로 아래와 같은 객체를 생성한다.
const element = { type: 'h1', props: { className: 'greeting', children: 'Hello, world!' } };
이러한 객체를 "React 엘리먼트"라고 하며, 이를 화면에 표시하려는 항목에 대한 설명이라고 생각할 수 있다.
엘리먼트 렌더링
엘리먼트는 React 앱의 가장 작은 단위
엘리먼트는 화면에 표시할 내용을 기술한다.
const element = <h1>Hello, world </h1>;
브라우저 DOM 엘리먼트와 달리 React 엘리먼트는 일반 객체(plain object)이며 쉽게 생성할 수 있다.
React DOM은 React 엘리먼트와 일치하도록 DOM을 업데이트한다.
DOM에 엘리먼트 렌더링하기
<div id = "root"> </div>
- 이 안에 들어가는 모든 엘리먼트를 React DOM에서 관리하기 때문에 이것을 루트(root) DOM 노드라고 부른다.
- React로 구현된 애플리케이션은 일반적으로 하나의 루트 DOM 노드가 있다.
- React 엘리먼트를 루트 DOM 노드에 렌더링하려면 둘 다 ReactDOM.render()로 전달하면 된다.
렌더링된 엘리먼트 업데이트하기
- React 엘리먼트는 불변객체이다. 엘리먼트를 생성한 이후에는 해당 엘리먼트의 자식이나 속성을 변경할 수 없다.
- React DOM은 해당 엘리먼트와 그 자식 엘리먼트를 이전의 엘리먼트와 비교하고 DOM을 원하는 상태로 만드는데 필요한 경우에만 DOM을 업데이트한다.
함수 컴포넌트와 클래스 컴포넌트
- 컴포넌트를 통해 UI를 재사용 가능한 개별적인 여러 조각으로 나누고, 각 조각을 개별적으로 살펴볼 수 있다.
- 개념적으로 컴포넌트는 javascript 함수와 유사하다.
- "props"라고 하는 임의의 입력을 받은 후, 화면에 어떻게 표시되는지를 기술하는 React 엘리먼트를 반환한다.
- 컴포넌트를 정의하는 가장 간단한 방법은 javascript 함수를 작성하는 것이다.
function welcome(props) { return <h1>Hello, {props.name}</h1>; }
이 함수는 데이터를 가진 하나의 "props(props는 속성을 나타내는 데이터)" 객체 인자를 받은 후 React 엘리먼트를 반환하므로 유효한 컴포넌트이다. 이러한 컴포넌트는 javascript 함수이기 때문에 말그대로 "함수 컴포넌트"라고 부른다.
또한 ES6 class를 사용하여 컴포넌트를 정의할 수 있다.
class Welcom extends React.component { render() { return <h1>Hello, {this.props.name}</h1>; } }
React의 관점에서 볼 때 위 두 가지 유형의 컴포넌트는 동일하다.
컴포넌트 렌더링
- React가 사용자 정의 컴포넌트로 작성한 엘리먼트를 발견하면 JSX 어트리뷰트를 해당 컴포넌트에 단일 객체로 전달한다. 이 객체를 "props"라고 한다.
- 컴포넌트의 이름은 항상 대문자로 시작한다.
컴포넌트 합성
- 컴포넌트는 자신의 출력에 다른 컴포넌트를 참조할 수 있다.
- React 앱에서는 버튼, 폼, 다이얼로그, 화면 등의 모든 것들이 흔히 컴포넌트로 표현된다.
- 일반적으로 새 React 앱은 최상위에 단일 App 컴포넌트를 가지고 있다.
- 기존 앱에 React를 통합하는 경우에는 Button 과 같은 작은 컴포넌트부터 시작해서 뷰 계층의 상단으로 올라가면서 점진적으로 작업해야 한다.
컴포넌트 추출
- 컴포넌트를 여러 개의 작은 컴포넌트로 나누기
function Comment(props) { return ( <div className="Comment"> <div className="UserInfo"> <img className="Avatar" src={props.author.avatarUrl} alt={props.author.name} /> <div className="UserInfo-name"> {props.author.name} </div> </div> <div className="Comment-text"> {props.text} </div> <div className="Comment-date"> {formatDate(props.date)} </div> </div> ); }
이 컴포넌트는 author(객체), text(문자열) 및 date(날짜)를 props로 받은 후 소셜 미디어 웹 사이트의 코멘트를 나타낸다.
이 컴포넌트는 구성요소들이 모두 중첩 구조로 이루어져 있어서 변경하기 어렵고, 각 구성 요소를 개별적으로 재사용하기도 힘들다.
Avatar 추출하기
function Avatar(props) { return ( <img className="Avatar" src={props.user.avatarUrl} alt={props.user.name} /> ); }
다음은 Avatar 옆에 사용자의 이름을 렌더링하는 UserInfo 컴포넌트를 추출한다.
function UserInfo(props) { return ( <div className="UserInfo"> <Avatar user={props.user} /> <div className="UserInfo-name"> {props.user.name} </div> ); }
기존의 Comment가 더욱 단순해졌다.
function Comment(props) { return ( <div className="Comment"> <UserInfo user={props.author} /> <div className="Comment-text"> {props.text} </div> <div className="Comment-date"> {formatDate(props.date)} </div> </div> ); }
컴포넌트를 추출하는 작업이 지루할 수 있다.
하지만 재사용 가능한 컴포넌트를 만드는 것은 더 큰 앱에서 작업할 때 두각을 나타낸다.
UI 일부가 여러번 사용되거나 (Button, Panel, Avatar), UI 일부가 자체적으로 복잡한 (App, FeedStory, Comment) 경우에는 재사용 가능한 컴포넌트를 만드는 것이 좋다.
props는 읽기 전용이다
함수 컴포넌트나 클래스 컴포넌트 모두 컴포넌트의 자체 props를 수정해서는 안된다.
순수 함수 : 입력값을 바꾸려 하지 않고 항상 동일한 입력값에 대해 동일한 결과를 반환하는 함수
function sum(a, b) { return a + b; }
아래 함수는 자신의 입력값을 변경하기 때문에 순수 함수가 아니다.
function withdraw(account, amount) { account.total -= amount; }
React는 매우 유연하지만 한 가지 엄격한 규칙이 있다.
모든 React 컴포넌트는 자신의 props를 다룰 때 반드시 순수 함수처럼 동작해야 한다.
애플리케이션 UI는 동적이며 시간에 따라 변한다. React 컴포넌트는 state를 통해 위 규칙을 위반하지 않고 사용자 액션, 네트워크 응답 및 다른 요소에 대한 응답으로 시간에 따라 자신의 출력값을 변경할 수 있다.
State 및 Lifecycle
function tick() { const element = ( <div> <h1> Hello, world! </h1> <h2> It is {new Date().toLocaleTimeString()}.</h2> </div> ); ReactDOM.render( element, document.getElementById('root') ); } setInterval(tick, 1000);
- Clock 구성 요소를 실제로 재사용하고 캡슐화하기
- 자체 타이머를 설정하고 매 초마다 업데이트한다.
- 시계를 캡슐화한다.
function Clock(props) { return ( <div> <h1>Hello, world!</h1> <h2>It is {props.date.toLocaleTimeString()}.</h2> </div> ); } function tick() { ReactDOM.render( <Clock date={new Date()} />, document.getElementById('root') ); } setInterval(tick, 1000);
함수를 클래스로 변환
- 시계와 같은 기능 구성요소를 다음 다섯 단계로 클래스로 변환할 수 있다.
- 리액트를 확장하는 동일한 이름을 가진 ES6 클래스를 만든다.
- render()라는 단일 빈 메소드를 추가한다.
- 함수의 본문을 render() 메서드로 이동시킨다.
- render() body에서 props를 this.props로 교체한다.
- 나머지 빈 함수 선언은 삭제한다.
class Clock extends React.Component { render() { return ( <div> <h1>Hello, world!</h1> <h2>It is {this.props.date.toLocaleTimeString()}.</h2> </div> ); } }
- Clock은 이제 함수보다는 클래스로 정의된다.
클래스에 Local State 추가
- date를 3단계에 걸쳐 props에서 state로 변경하기
render() method에서 this.props.date를 this.state.date로 교체한다.
class Clock extends React.Component { render() { return ( <div> <h1>Hello, world! </h1> <h2>It is {this.state.date.toLocaleTimeString()}.</h2> </div> ); } }
this.state를 초기화하는 클래스 생성자를 추가한다.
class Clock extends React.Component { constructor(props) { super(props); this.state = {date: new Date()}; } render() { return ( <div> <h1>Hello, world!</h1> <h2>It is {this.state.date.toLocaleTimeString()}.</h2> </div> ); } }
엘리먼트로부터 date prop을 제거한다.
ReactDOM>render( <Clock />, document.getElementById('root') );
- 결과 코드는 다음과 같다.
class Clock extends React.Component { constructor(props) { super(props); this.state = {date: new Date()}; } render() { return ( <div> <h1> Hello, world!</h1> <h2> It is {this.state.date.toLocaleTimeString()}.</h2> </div> ); } } ReactDOM.render( <Clock />, document.getElementById('root') );
클래스에 라이프 사이클 메소드 추가
- Clock 이 처음으로 DOM에 렌더링될 때마다 타이머를 설정하기를 원한다. 이것을 리액트에서는 마운팅이라고 한다.
- Clock에
반응형'React' 카테고리의 다른 글
[React] 배열 데이터 렌더링 및 관리 (0) 2019.05.06 [React] Input 상태 관리 (0) 2019.05.03 [React] 리액트 작업 환경 설정하기 (0) 2019.05.01 [React] LifeCycle 소개 및 사용법 (0) 2019.05.01 [React] 리액트는 무엇인가_01 (0) 2019.04.16