본 글은 생활코딩 「React 2022 개정판」 영상을 보고 간단히 정리한 글이다.
React 환경설정
- Node.js 설치
- nodejs.org 사이트에 들어가서 Node.js를 설치한다. 현시점 버전은 v16.14.2
- create-react-app을 이용한 React 프로젝트 설치
npx create-react-app .
.은 현재 디렉토리를 뜻한다.
소스코드 수정 방법
index.js가 기본 파일이다.
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
여기서 <App /> 이라는 태그가 UI 전체다. (웹 브라우저 화면의 모든 것)
App의 실제 내용은 App.js에 있다. 상단에 보면 import App from './App'; 이라는 코드가 있는데 해당 파일에서 가져오는 것.
정리
- src/index.js가 입구다. 이 안에 여러가지 전역적인 설정들이 들어간다.
- App.js를 수정해가며 UI를 만들어간다.
그런데 자세히 보면 App을 감싸고 있는 roor라는 id의 태그가 있다.
public 폴더 안의 index.html을 보면 id가 root인 태그가 있다. 해당 html 파일의 태그 안에 App.js의 코드를 넣는 것.
배포
빌드
npm run build
yarn build
- build 폴더가 생긴다. 안의 index.html을 보면 코드가 최대로 압축되어 있다.
배포
serve -s build
컴포넌트
React는 사용자 정의 태그를 만드는 기술이다.
만약 비슷한 형식의 코드가 몇백만 줄이 있다면, 그 코드는 파악하기 매우 어려울 것이다.
React에서는 서로 연관된 코드끼리 모아서 이름을 붙이는 사용자 정의 태그를 만들 수 있다.
컴포넌트(=사용자 정의 태그)를 만드는 법
기본 형식
function 태그이름() { // 태그 이름은 반드시 대문자로 시작한다.
return `html 태그`;
}
function Header() {
return (
<header>
<h1><a href='/'>WEB</a></h1>
</header>
);
}
컴포넌트를 재사용하고 공유함으로서 생산성을 획기적으로 끌어올릴 수 있다.
props
리액트에서 속성.
사용법은 다음과 같다.
<Article title='Welcome' body='Hello, React'></Article>
컴포넌트를 사용하는 쪽에서 이렇게 값을 넘기면,
function Article(props) {
return (
<article>
<h2>{props.title}</h2>
{props.body}
</article>
);
}
props와 중괄호{ }로 받아서 처리한다.
그럼 목록과 같은 내용은 어떻게 전달할까?
const topics = [
{ id: 1, title: 'html', body: 'html is...' },
{ id: 2, title: 'css', body: 'css is...' },
{ id: 3, title: 'js', body: 'js is...' },
];
먼저 부모 컴포넌트에서 위와 같이 값을 선언한 다음,
<Nav topics={topics}></Nav>
이렇게 값을 넘긴다. 이때 주의할 점은, 단순히 topics="topics"로 넘기면 topics가 string으로 넘어간다. topics list를 그대로 넘기고 싶으면 중괄호{ }에 담아야 한다.
function Nav(props) {
let list = [];
for (let i = 0; i < props.topics.length; i++) {
let t = props.topics[i];
list.push(<li><a href={'/read/' + t.id}>{t.title}</a></li>);
}
return (
<nav><ol>{list}</ol></nav>
);
}
그리고 이렇게 받는 컴포넌트 쪽에서 데이터를 담아 html 태그를 생성하여 return 하면 된다.
그런데 여기서 주의할 점이 하나가 있다. 위와 같이 코드를 짜면 다음과 같은 오류가 생긴다.
Warning: Each child in a list should have a unique "key" prop.
list의 각 자식은 key라는 고유한 속성을 가지고 있어야 한다는 뜻이다.
따라서 아래와 같이 key 값을 설정해주어야 한다.
list.push(
<li key={t.id}><a id={t.id} href={'/read/' + t.id}>{t.title}</a></li>
);
이벤트
<input type="button" onclick="alert('hi')">
React에선 위와 같은 이벤트를 어떻게 사용할까?
<Header title='Web' onChangeMode={function () {
alert('hi');
}}></Header>
우선 부모 컴포넌트에서는 이렇게 onChangeMode에 실행할 함수를 넣어주고,
<header>
<h1>
<a href='/' onClick={function (event) {
event.preventDefault();
props.onChangeMode();
}}>{props.title}</a>
</h1>
</header>
자식 컴포넌트에서는 onClick 으로 클릭이벤트 발생시 실행할 함수를 호출한다. (onChangeMode가 가리키는)
이때 페이지 리로드가 일어나지 않도록 하기 위해서는, React가 콜백함수 호출시 첫번째로 전달해주는 event 객체를 사용해서 event.preventDefault();를 실행한다. (=기본동작 방지. 새로고침 안일어남.)
이벤트 함수에 파라미터를 전달하고 싶다면 다음과 같이 하면 된다.
// 호출하는 쪽
onChangeMode={(id) => {
alert(id);
}}
// 호출받는 쪽
onClick={(event) => {
event.preventDefault();
props.onChangeMode(event.target.id);
}}
state
props와 함께 컴포넌트를 다시 실행해서 새로운 리턴값을 만들어주는 또 하나의 데이터.
차이점은 props는 컴포넌트를 사용하는 외부자를 위한 데이터고, state는 컴포넌트를 만드는 내부자를 위한 데이터다.
상태값이 변경됨에 따라 컴포넌트가 다시 실행되어 새로운 UI를 보여주고 싶을때, state를 사용한다. 이를 위해서는 useState라는 훅을 이용해야 한다.
import { useState } from 'react';
function App() {
const _mode = useState('WELCOME');
...
}
위에서 _mode를 콘솔로 출력해보면 이렇게 뜬다.
useState는 배열을 리턴한다. 0번째 원소는 상태의 값이고, 1번째 원소는 상태를 변경할 때 사용하는 함수다.
const [mode, setMode] = userState('WELCOME');
보통은 위와 같이 간단하게 쓴다.
총정리하면 다음과 같다.
function App() {
const [mode, setMode] = useState('WELCOME');
const [id, setId] = useState(null);
const topics = [
{ id: 1, title: 'html', body: 'html is...' },
{ id: 2, title: 'css', body: 'css is...' },
{ id: 3, title: 'js', body: 'js is...' },
];
let content = null;
if (mode === 'WELCOME') {
content = <Article title='Welcome' body='Hello, WEB'></Article>;
} else if (mode === 'READ') {
let title,
body = null;
for (let i = 0; i < topics.length; i++) {
console.log(topics[i].id, id);
if (topics[i].id === id) {
title = topics[i].title;
body = topics[i].body;
}
}
content = <Article title={title} body={body}></Article>;
}
return (
<div>
<Header
title='Web'
onChangeMode={() => {
setMode('WELCOME');
}}></Header>
<Nav
topics={topics}
onChangeMode={(_id) => {
setMode('READ');
setId(_id);
}}></Nav>
{content}
</div>
);
}
그리고 추가로 onChangeMode에서 넘어오는 id 값은 (=event.targeet.id) string으로 넘어오기 때문에 숫자형태로 바꿔줘야 한다.
props.onChangeMode(Number(event.target.id));