: React는 사용자 인터페이스를 만들기 위한 JavaScript 라이브러리다.
리엑트는 자바 스크립트에서 가장 유명한 라이브러리 중 하나이다. 많은 개발자들이 배우고, 코드 스테이츠에서도 가장 중요한 스프린트라고 강조하고 있다.
리액트를 사용하여 우리가 얻을 수 있는 이익은 HTML 트리구조를 보기 좋게 모듈화 시켜 내가 원하는기능만을 쉽게 가져다가 사용할 수 있다는 장점이 있다. 또한 이렇게 모듈화로 저장을 해두면 유지 보수가 쉬워진다.
리엑트는 JS의 라이브러리지만, JSX라는 자바 스크립트 확장형 문법을 사용하고 있고, 자바 스크립트 문법을 사용하려면 {} 안에서 사용 가능하다.
: JSX란 리엑트를 쉽고 편하게 사용하게 해주는 자바스크립트 확장 문법이다.
리엑트에서 무조건 JSX를 사용해야하는것은 아니지만, 사용하면 여러가지 장점이 있다.( 자바 스크립트 문법으로도 리엑트를 사용할 수 있지만, JSX를 추천한다.)
반드시 하나의 엘리먼트로 감싸야한다.
예)
내부에 JS 코드를 작성할 수 있는데, 이때 중괄호 안에 작성해야한다.
예)
JSX내부에서는 if문을 사용 할 수 없다. 그래서 우리는 IIFE 또는 삼항연산자를 사용해야한다.
예)
엘리먼트의 클래스 이름을 적을 때,class대신에 className이라고 적는다.
예)
function formatName(user) { return user.firstName + ' ' + user.lastName; } const user = { firstName: 'Harper', lastName: 'Perez' }; const element = ( <h1> Hello, {formatName(user)}! // { }를 사용하여 JS를 사용 가능하게 한다. </h1> ); ReactDOM.render( // DOM에 렌더를 시키는 함수 element, // 렌더 함수 첫번째 인자로 내가 넣고 싶은 엘리먼트를 넣는다 document.getElementById('root') // 두번째 인자로 내가 넣을 위치를 정한다. );
props(속성)에 따옴표를 이용해 HTTML처럼 문자열을 넣을 수 있다.
const element = <div tabIndex="0"></div>;
또 중괄호를 사용하여 JavaScript 표현식을 사용 할 수도 있다.
const element = <img src={user.avatarUrl}></img>;
** 주의
JavaScript 표현식을 삽입할 때 중괄호 주변에 따옴표를 입력하지 마세요. 따옴표(문자열 값에 사용) 또는 중괄호(표현식에 사용) 중 하나만 사용하고, 동일한 어트리뷰트에 두 가지를 동시에 사용하면 안된다.
src=https://www.youtube.com/embed/ + {props.video.id.videoId}
내가 과제를 할때, 어트리뷰트(아래 코드에서는 src를 뜻함)에 어떻게 문자열과 JSX를 같이 넣을 수 있을까 고민했었다. 처음에는 여러가지 시도를 했었다. 예를들어서
src=https://www.youtube.com/embed/ + {props.video.id.videoId}
// 또는
src={"https://www.youtube.com/embed/" + {props.video.id.videoId}}
그러나 이렇게 막 섞거나 더하기를 사용하지않고, 아래의 코드로 사용하여 과제를 해결 할 수 있었다.
src={`https://www.youtube.com/embed/${props.video.id.videoId}`}
JSX를 객체로 나타내기
const element = ( <h1 className="greeting"> Hello, world! </h1> ); // === (위 아래 코드는 같은것을 나타낸다.) const element = React.createElement( 'h1', {className: 'greeting'}, 'Hello, world!' );
이 아래의 코드는 위의 두 코드와 같지만, 단순 JS로만 작성되어있다.
const element = { type: 'h1', props: { className: 'greeting', children: 'Hello, world!' } };
이렇게 순수 JS 객체로 이해하면, 위의 두 코드를 이해하기 쉽다.
: 엘리먼트는 React 앱의 가장 작은 단위이고, 엘리먼트는 화면에 표시할 내용을 기술한다. 주의 할 점은 브라우저 DOM 엘리먼트와 다르게 React 엘리먼트는 '일반 객체(plain object)'이며 불변(immutable) 객체이다.
// HTML 파일에 `<div>를 생성하고 아이디를 root를 지정한다. <div id="root"></div> // function tick() { const element = ( <div> <h1>Hello, world!</h1> <h2>It is {new Date().toLocaleTimeString()}.</h2> </div> ); // React 엘리먼트를 루트 DOM 노드에 렌더링하기 위해 // ReactDOM.render()를 사용하여 전달. ReactDOM.render(element, document.getElementById('root')); } // 1초마다 tick 함수를 실행 setInterval(tick, 1000);
: 컴포넌트란, 우리가 CommonJS에서 배운 모듈과 같은 역할을 한다. 컴포넌트를 만들어 놓으면 우리가 사용하고 싶은곳에서 재사용할 수 있다.
이런 컴포넌트에는 두가지 타입의 컴포넌트가 존재한다. 함수 컴포넌트와 클래스 컴포넌트다.
두 컴포넌트는 차이점이 있다.
함수 컴포넌트
: 함수 컴포넌트란, 쉽게 말해 JavaScript 함수를 작성하는 것이다. 주로 인자로 props(속성)을 받는다. 함수컴포넌트는 클래스 컴포넌트와 다르게 state를 가지고 있지 않다.(사실 React Hook에서는 state를 가질 수 있다.)
여기서 props란 코드에 A부분쪽에 적힌 Welcome 엘리먼트의 name과 content를 의미한다. 그래서 props.name 는 DH을 뜻하고 props.contents는 Hi, React를 가르킨다.
props에 알아야할 중요한 특성
1. props는 읽기 전용이다. 다시 말해, 불변성 이기때문에 바꿀 수 없어야한다는 것이다.
2. props는 외부로 전달 받은 값이다.
function Welcome(props) { return <h1>Hello, {props.name}</h1>; } <Welcome name='DH' content='Hi, React'></Welcome> // A(props) // Hello, DH
클래스 컴포넌트
: ES6 class를 사용하여 컴포넌트를 정의할 수 있다.
class Welcome extends React.Component { constructor(){ super(props); this.state = { items: []; }; } render() { return <h1>Hello, {this.props.name}</h1>; } }
** 여기서 중요한점
1. 두 종류 컴포넌트는 항상 대문자로 시작한다. 예) Welcome
2. class 컴포넌트는 내부에 constructor와 render 함수를 가진다.
또 constructor는 super(props)를 받고 this.state를 사용할 수 있다.
render는 렌더해주는 메소드로써 react엘리먼트를 리턴한다.
: Lifecycle은 우리의 삶과 매우 흡사하다.
컴포넌트들도 중요한 순간을 가지게 되는데
위의 그림을 좀 더 자세하게 다이어그램으로 나타내면 아래와 같은 그림이 된다. 아래의 그림은 외워두는것이 좋다. 아주 중요 !
초보자에게 위의 그림이 무엇을 뜻하는지 이해가 안갈수 있다.
아래는 on/off 버튼을 나타내는 코드이다.
import React from "react"; import ReactDOM from "react-dom"; // function App() { return ( <div className="App"> <h1>아래 버튼을 눌러보세요</h1> <Button /> </div> ); } class Button extends React.Component { constructor(props) { super(props); this.state = { isOn: false }; console.log("constructor로 생성"); // constructor를 생성 할때 this.handler = this.handler.bind(this); } handler() { this.setState((state) => ({ isOn: !state.isOn })); } componentDidMount(){ console.log('화면에 등장(mount)') } componentDidUpdate(){ console.log('새로운것 업데이트(update)') } render() { console.log("렌더링!"); // 렌더링 할때 return ( <div> <button onClick={this.handler}>{this.state.isOn ? "ON" : "OFF"}</button> </div> ); } } // const rootElement = document.getElementById("root"); ReactDOM.render( <App />, rootElement );
이렇게 코드만 작성하고 콘솔창을 열어보면 아래와 같은 문구를 볼 수 있다.
먼저 constructor에 있는 콘솔이 먼저 실행되어서 "constructor로 생성" 의 문구를 출력하였고, 다음에는 render 함수가 실행되었다. 그리고 렌더링이 된 후, componentDidMount 함수가 실행되는 것을 볼 수 있다.
이것을 위의 그림의 가장 왼쪽에 있는 박스이다. 생성될때 이런 주기로 생성이 된다. 그러면 update는 무엇일까 ? on/off 버튼을 누르면 무슨 일이 나타나는지 보자
버튼을 누르닌까, render함수가 실행되고 componentDidUpdate 함수가 실행되었다.
위의 그림에서 3가지로 상태를 변화 시키는 방법이 있는데 나는 그 중에서 setState를 사용하였다. 공식문서에서 state를 변경시킬때는 setState를 사용하라고 한다. 직접적으로 바꾸지말고. 그 이유가 이 Lifecycle과 관련이 있기 때문이다.
간략하게 다시 적으면,
위와 같은 메소드를 “생명주기 메소드” 라고 부른다.
: 공식문서에서 직접 State를 수정하지 말라고 말한다.
예를 들어 this.state.comment = 'Hello';
이렇게 직접적으로 바꾸게 되면, 컴포넌트를 다시 render하지 않기 때문이다.
그렇게 때문에 우리는 setState를 사용하고,
this.setState({comment: 'Hello'});
라고 적어주어야한다.
this.state
를 지정할 수 있는 유일한 공간은 constructor
다.