유저와 많은 인터랙션이 발생함으로 인하여 상태 변화 관리가 필요해졌다. 이러한 상태 변화 관리에 대한 부담이 커지다보니 개발자가 좀더 '기능 개발'에 집중하기 위한 환경이 요구되었고, 이에 따라 많은 프레임워크와 라이브러리가 나타났다. React는 그렇게 나타난 라이브러리 중 하나이다.
Virtual DOM은 가상의 DOM으로 변화가 일어나면 실제 브라우저에 DOM을 넣는 것이 아니라, 자바스크립트로 이뤄진 가상 DOM 에 한번 렌더링을 하고, 기존의 DOM 과 비교를 한 다음에 정말 변화가 필요한 곳에만 업데이트를 해주는 것이다. 앞서 React 탄생 배경에서 언급했던 '유저의 인터랙션에 의한 상태 변화로 인한 비효율성'을 최소화하기 위해 탄생하게 된 것이다. → 연산 횟수 감소 = 연산 비용 감소
JSX는 (Javascript + XML)는 XML 형식의 값을 반환해주는 자바스크립트 확장 문법이다. XML 형태로 코드를 작성하면 babel이 JavaScript 형태로 반환을 해주는데 이 모양이 어떤지 확인하고자 한다면 '여기' 를 클릭하여 확인할 수 있다. React에서 JSX문법을 활용한다면 반드시 JSX로 반환해야한다.
className
으로 표기하여 사용한다. → ES6에서 Class가 존재하기 때문JSX의 중괄호 안에 유효한 모든 Javascript 표현식을 넣을 수 있다.
const name = 'Josh Perez';
//name 이라는 변수를 선언 후, 중괄호로 감싸서 사용했다.
const element = <h1>Hello, {name}</h1>;
function formatName(user) {
return user.firstName + ' ' + user.lastName;
}
const user = {
firstName: 'Harper',
lastName: 'Perez'
};
//엘리먼트 안에 formatName 함수 호출 사용
const element = (
<h1>
Hello, {formatName(user)}!
</h1>
);
ReactDOM.render(
element,
document.getElementById('root')
);
컴파일이 끝나면, JSX 표현식이 정규 JavaScript 함수 호출이 되고 JavaScript 객체로 인식된다.
/>
를 이용해 바로 닫아줘야한다.const element = <img src={user.avatarUrl} />;
const element = (
<div>
<h1>Hello!</h1>
<h2>Good to see you here.</h2>
</div>
);
빌드환경에서 컴파일 설정을 하고 싶지 않을 때, JSX없이 React를 사용하는 것이 특히 편리하다.
각 JSX 엘리먼트는 React.createElement(component, props, ...children)
를 호출 하기 위한 문법 설탕(syntactic sugar) 이다. 그래서 JSX로 할 수 있는 모든 것은 순수 JavaScript로도 할 수 있다.
//JSX코드
class Hello extends React.Component {
render() {
return <div>Hello {this.props.toWhat}</div>;
}
}
ReactDOM.render(
<Hello toWhat="World" />,
document.getElementById('root')
);
//JSX를 사용하지 않는 코드
class Hello extends React.Component {
render() {
return React.createElement('div', null, `Hello ${this.props.toWhat}`);
}
}
ReactDOM.render(
React.createElement(Hello, {toWhat: 'World'}, null),
document.getElementById('root')
);
React를 사용하기 앞서, Codesandbox 를 통해 React를 간접적으로 체험할 수 있다. 이를 통해서 연습을 진행해보고, 실제 내 컴퓨터에 React 개발환경을 구축하여 활용해나갈 수 있다.
공식에서 추천하는 npx
를 사용하도록 하자. npm install -g create-react-app
도 가능하지만, npx는 컴퓨터 공간을 차지 하지 않게 한번만 설치 후 삭제가 되고, 설치 할 때마다 새롭게 깔리기 때문에 항상 최신 상태를 유지 시켜준다.
npx create-react-app my-app
cd my-app
// 아래 명령어를 통해 http://localhost:3000 가 실행되고 react 샘플웹화면이 잘 보인다면 설치가 성공!
npm start
// 또한 아래 명령어를 통해 버전 확인 가능
create-react-app -V
폴더를 이미 만들었다면, 폴더 안에 들어가서 터미널 실행 후, create-react-app .
을 눌러주면 해당 폴더 안에서 react 환경 세팅을 진행해줄 수 있다.
앞서 Codesandbox나 vs 코드 안에서 볼 수 있는 기본 구조를 그려보았고, 흐름은 아래와 같다.
<App />
를 렌더링하도록 public 폴더에 있는 index.html에 전달한다.<div>
요소 'root' 안에 리액트 컴포넌트가 들어가 브라우저에 출력된다.그럼 각각의 역할들에 대해서 좀더 자세하게 알아보자.
<div id="root"></div>
안에 들어가는 모든 엘리먼트는 ReactDOM에서 관리하기 때문에 이를 루트(root) DOM 노드라고 부른다.React 안에서 컴포넌트를 정의하는 방식은 2가지가 있다.
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
const element = <Welcome name="Sara" />;
순수함수 : 입력값을 바꾸려 하지 않고 항상 동일한 입력값에 대해 동일한 결과를 반환하는 함수
props 내부의 값을 조회 할 때마다 props. 를 입력하고 있는데, 함수의 파라미터에서 비구조화 할당 (혹은 구조 분해라고도 불립니다) 문법을 사용하면 조금 더 코드를 간결하게 작성할 수 있다.
//props로 할당
function Hello(props) {
console.log(props);
return <div style={{ color: props.color }}>안녕하세요 {props.name}</div>;
}
//구조분해할당
function Hello({name, color}) {
console.log(arguments);
return <div style={{ color }}>안녕하세요 {name}</div>;
}
props를 지정하지 않았을 때, 기본적으로 사용할 값을 설정하면 defaultProps
를 설정한다.
function Hello({ color, name }) {
return <div style={{ color }}>안녕하세요 {name}</div>
}
Hello.defaultProps = {
name: '이름없음'
}
컴포넌트 태그 사이에 넣은 값을 조회하고자 할 때는 props.children
을 조회하면 된다.
React에서 컴포넌트가 여러 엘리먼트를 반환하고자 할 때, DOM에 별도의 노드를 추가하지 않고 여러자식을 그룹화할 수 있는데 이것이 바로 Fragments
이다.
class Columns extends React.Component {
render() {
return (
<React.Fragment>
<td>Hello</td>
<td>World</td>
</React.Fragment>
);
}
}
//단축문법
class Columns extends React.Component {
render() {
return (
<>
<td>Hello</td>
<td>World</td>
</>
);
}
}
컴포넌트 사용 중 컴포넌트 내부에서 변할 수 있는 값으로 '상태'라고 하는데 알 수 없는 '비공개된' 부분이며 컴포넌트에 의해 완전히 제어된다. 이를 소유한 컴포넌트 이외에는 어떠한 컴포넌트가 접근할 수 없어서 '로컬' 또는 '캡슐화'라고 불린다.
props는 인자처럼 외부로부터 전달받은 값이지만 state는 내부에서 변화하는 값이다.
언제 이 두가지를 활용해야하는지 잘 알아야한다. 자세한 차이점을 알아보자.
state와 props의 형태는 '객체'이며, 렌더링 결과물에 영향을 주는 정보를 갖고 있는 것이 공통점이지만, 차이점이 있다.
props | state | |
---|---|---|
부모컴포넌트로부터 초기값을 얻을 수 있는가? | YES | YES |
부모컴포넌트에 의해 변경될 수 있는가? | YES | NO |
컴포넌트 내부에서 초기값을 설정할 수 있는가? | YES | YES |
컴포넌트 내에서 변화할 수 있는가? | NO | YES |
하위 컴포넌트에서 초기값을 설정할 수 있는가? | YES | YES |
하위 컴포넌트를 변경할 수 있는가? | YES | NO |
state에 대한 추가내용으로 넘어가기 → React - state & Lifecycle
컴포넌트 안에 리스트를 렌더링한다. 배열을 사용해서 활용할 수 있다.
경고 메세지 : Warning: Each child in a list should have a unique "key" prop.
리스트의 각 항목에 "key"를 넣어야한다는 경고 표시인데, 이 누락 문제를 해결하기 위해서는 리스트의 각 항목에 "key"를 부여해줘야 한다. 그렇다면 "key"는 무엇일까?
“key”는 엘리먼트 리스트를 만들 때 포함해야 하는 특수한 문자열 어트리뷰트를 나타낸다. React가 어떤 항목을 변경, 추가 또는 삭제할지 식별하는 것을 돕는 역할을 하며, 엘리먼트에 안정적인 고유성을 부여하기 위해 배열 내부의 엘리먼트에 지정해야 한다. 리스트의 개별 항목을 고유하게 식별할 수 있기 위해 대부분 데이터의 ID 를 key로 사용한다.
const todoItems = todos.map((todo) =>
<li key={todo.id}>
{todo.text}
</li>
);
렌더링 한 항목에 대한 안정적인 ID가 없다면 최후의 수단으로 항목의 인덱스(index) 를 key로 사용할 수 있지만 권장하지 않습니다
const todoItems = todos.map((todo, index) =>
// Only do this if items have no stable IDs
<li key={index}>
{todo.text}
</li>
);
background-color
처럼 -
로 구분되어 있는 이름들은 backgroundColor
처럼 camelCase 형태로 네이밍function App(){
const name = 'react';
const style = {
backgroundColor: 'black',
color: 'aqua',
}
return (
<div style={style}>{name}</div>
);
}
import "./파일명.css"
로 CSS를 연결해준 후, className
을 통해 스타일을 할당해주면 적용된다.JSX 내부의 주석은 {/* 이런 형태로 */}
작성해야한다. 중괄호로 작성하지 않으면 주석이 보인다.
열려있는 내부 태그 안에서는 //
를 써서 활용할 수 있다.
ES6 및 JSX 코드가 올바르게 표시되도록 편집기에 “Babel” 언어 설정을 사용하는 것을 권장한다고 공식문서에 나와있다.
크롬 확장을 통해, 좀더 React 를 디버깅하거나 쉽게 사용해나갈 수 있다.
설치를 완료하면 크롬 개발자 툴안에 "⚛️ Components" 과 "⚛️ Profiler" 탭이 추가되어 있는 것을 확인할 수 있다.
Components 탭에서는 root React 컴포넌트를 확인할 수 있다.
React 입문용 참조사이트
1. ★공식문서
2. React - 생활코딩 Youtube , 홈페이지
3. 벨로퍼트와 함께하는 모던 리액트