### 사전 지식
- HTML / CSS 기초
- 자바스크립트 기초
- 함수형 프로그래밍과 고차 함수 개념에 대한 이해
- 배열 내장 메서드 기초
- ES6 문법에 대한 이해
## React intro
### 목표
- React의 3가지 특징에 대해서 이해하고, 설명할 수 있다.
- JSX가 왜 명시적 인지 이해하고, 바르게 작성할 수 있다.
- React 컴포넌트(React Component)의 필요성에 대해서 이해하고, 설명할 수 있다.
- create-react-app으로 간단한 개발용 React 앱을 실행할 수 있다.
JSX란?
React에서 UI를 구성할 때 사용하는 문법으로, JS를 확장한 문법이다. 이 문법을 통해 React element를 만들 수 있다.
하지만 브라우저는 JSX를 읽을 수 없기 때문에 Babel을 통해서 JSX를 JS로 컴파일하여 브라우저가 읽을 수 있게 만들어준다.
React 에서는 DOM과 다르게 CSS, JSX 문법만을 가지고 웹 어플리케이션을 만들 수 있다.( DOM에 비해서 제작이 필요한 파일 한 개가 줄어든다는 장점 )
구조와 동작에 대한 코드를 한 뭉치로 적은 코드셋을 컴포넌트라고 한다.
JSX없이도 React element를 만들수 있긴 하지만, 가독성이 떨어진다.
JSX 활용
JSX 규칙 중 하나로 하나의 엘리먼트 안에 모든 엘리먼트가 포함되어야 한다.
엘리먼트 사용 시, "class"가 아닌 "className"으로 표시한다. 만약 class라고 표시한다면 JS 클래스로 인식하게 된다.
JSX에서 JS를 사용하고자 한다면, 꼭 중괄호를 사용해야 한다. 중괄호를 사용하지 않으면 일반 텍스트로 간주한다.
React 엘리먼트가 JSX로 작성되면 "대문자"로 시작해야 한다. 소문자로 시작하면 일반적인 html 엘리먼트로 인식한다.
이렇게 대문자로 작성된 JSX 컴포넌트를 따로 사용자 정의 컴포넌트라고 부른다.
조건부 렌더링에는 if 문이 아닌 삼항연산자를 사용한다.
여러 개의 HTML 엘리먼트를 표시할 때는 "map()" 함수를 사용한다. map 함수를 사용할 때는 반드시 "key" JSX 속성을 넣어야 한다.
↓
map을 이용한 반복
다시 짚어보는 map의 특성
- 배열의 각 요소를
- 특정 논리(함수)에 의해
- 다른 요소로 지정(map)합니다.
React에서 map 메소드 사용 시, key 속성을 넣지 않으면 위와 같이 리스트의 각 항목에 key를 넣어야 한다는 경고가 표시된다. key 속성의 위치는 map 메소드 내부에 있는 엘리먼트 즉, 첫 엘리먼트에 넣어야 한다.
알아야 할 사항
key 속성 값이 반드시 id가 되어야 하나요? id가 존재하지 않으면 어떻게 해야 하나요? key 속성값은 가능하면 데이터에서 제공하는 id를 할당해야 합니다. key 속성값은 id와 마찬가지로 변하지 않고, 예상 가능하며, 유일해야 하기 때문입니다. 정 고유한 id가 없는 경우에만 배열 인덱스를 넣어서 해결할 수 있습니다. 배열 인덱스는 최후의 수단(as a last resort)으로만 사용합니다. 리액트 공식문서의 key에서 추가로 공부하세요.
function Blog() {
// postToElement라는 함수로 나누지 않고 아래와 같이 써도 무방합니다.
const blogs = posts.map((post) => (
<div key={post.id}>
<h3>{post.title}</h3>
<p>{post.content}</p>
</div>
));
return <div className="post-wrapper">{blogs}</div>;
}
위 코드는 올바른 key 속성 값 할당 예시이다.
Component-Based
지금까지 배운 것을 바탕으로 간단한 실습을 해보았다.
실습 전 제작 terminal에서
$ npx create-react-app 원하는 폴더명
를 작성하여 기본적인 React tool를 설치하도록 한다.
배운 것을 활용하여 만들어본 Twittler 화면 ↑
const Sidebar = () => {
return (
<section className="sidebar">
<i className="far fa-comment-dots"></i>
<FontAwesomeIcon className="far" icon={faBell} size="2x" />
</section>
);
};
사이드바는 font awesome을 이용하여 아이콘을 삽입하였다. 아이콘1은 React를 이용하였고, 아이콘2는 html 태그로 가져오는 방식을 택하였다. React에 font awesome 설치하기
const Counter = () => {
return (
<div className="tweetForm__input">
<div className="tweetForm__inputWrapper">
<div className="tweetForm__count" role="status">
total:{dummyTweets.length}
</div>
</div>
</div>
);
};
카운터에는 게시물의 개수를 표시하기 위해 데이터에 length를 붙였다.
const Footer = () => {
return (
<div>
<footer>Copyright @ {new Date().getFullYear()} Code States</footer>
</div>
);
};
Footer에는 현재 년도가 표시되도록 getFullYear()를 활용했다.
const Tweets = () => {
return (
<ul className="tweets">
{dummyTweets.map((tweet) => {
const isParkHacker = tweet.username === "parkhacker";
const tweetUserNameClass = isParkHacker
? "tweet__username tweet__username--purple"
: "tweet__username";
return (
<li className="tweet" key={tweet.id}>
<div className="tweet__profile">
{/* 프로필 사진 */}
<img src={tweet.picture} />
</div>
<div className="tweet__content">
<div className="tweet__userInfo">
{/* 이름이 "parkhacker"인 경우, 이름 배경색을 rgb(235, 229, 249)으로 바꾼다 */}
<span className={tweetUserNameClass}>{tweet.username}</span>
{/* 생성일자 */}
<span className="tweet__createdAt">{tweet.createdAt}</span>
</div>
<div className="tweet__message">{tweet.content}</div>
</div>
</li>
);
})}
</ul>
);
};
메인 content에는 프로필 사진, 이름, 내용, 생성 날짜가 나오도록 작성하였다. 추가적으로 이름에 parkhacker인 경우 이름 배경색을 변경해 보았다. (filter 사용)
const Features = () => {
return (
<section className="features">
<div className="tweetForm__container">
<div className="tweetForm__wrapper">
<div className="tweetForm__profile"></div>
<Counter />
</div>
</div>
<Tweets />
<Footer />
</section>
);
};
const App = () => {
return (
<div className="App">
<main>
<Sidebar />
<Features />
</main>
</div>
);
};
만들었던 사용자 정의 컴포넌트를 통합시켰다.
추가 작업으로 사이드바에 여러 버튼을 만들고 클릭 시 Tweets 내용이 변경되도록 하려했는데, React 남은 기초과정 후에 다시 진행해 보도록 한다. state, state hooks, props에 대해서 알아보자.
## React SPA
### 목표
- SPA(Single-Page Application) 개념을 이해하고 설명할 수 있다.
- SPA의 장, 단점에 대해 이해하고 설명할 수 있다.
- 와이어프레임을 보고 어느 부분을 컴포넌트로 구분해야 할지 스스로 정할 수 있다.
SPA 등장 배경과 개념
전통적인 웹사이트는 페이지 이동 시 매번 "페이지 전체"를 불러야 했다.
SPA는 페이지 전환 전후 중복되는 부분은 새로 불러오지 않는다. <- 불필요한 트래픽을 발생시키지 않는다.
즉 SPA는 서버로부터 완전히 새로운 페이지를 불러오는 것이 아니라, 화면을 업데이트하기 위해 필요한 데이터만 서버에서 전달 받아 브라우저에서 해당하는 부분만 업데이트하는 방식으로 작동하는 웹 애플리케이션이나 웹 사이트를 말한다.
장점
사용자의 행동에 빠르게 반응한다. 서버 과부하 문제도 현저히 줄일 수 있다. ex) Youtube, facebook, Gmail, Netflix
단점
JS파일이 크기가 커지게 되어 첫 화면 로딩 시 JS파일을 기다리는 시간으로 인해 로딩 시간이 길어진다.
검색 엔진 최적화가 좋지 않다.(html 파일 자료를 분석하는 방식으로 검색 기능을 구동하는데 SPA는 html에는 별다른 자료가 없기 때문에 활용하기 어려움)
## React Router
### 목표
- React에서 npm으로 React Router DOM을 설치(npm install react-router-dom)하고 이용할 수 있다.
- React Router DOM를 이용하여 SPA를 구현할 수 있다.
- 라우팅 구조를 짤 수 있어야 하고, 이에 필요한 기초 문법들을 사용할 수 있어야 한다.
SPA & Routing
사진과 같이 다른 주소에 따라 다른 뷰를 보여주는 과정을 "경로에 따라 변경한다." 라는 의미로 Routing이라고 한다.
React SPA에서는 라우팅을 위해 React Router 라는 라이브러리를 가장 많이 사용한다.
개념들을 간단하게 정리하자면,
BrowserRouter
웹 애플리케이션에서 페이지를 새로고침하지 않고도 주소를 변경할 수 있는 역할을 해준다.
아래와 같이 ReactDOM의 랜더 단계인 index.js 에 넣어서 활용할 수도 있다.
BrowserRouter가 상위에 작성되어 있어야 Route 컴포넌트를 사용할 수 있다.
index.js ↓
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
ReactDOM.render(<BrowserRouter><App/></BrowserRouter>, document.querySelector('#root'));
Switch, Route
경로를 매칭해주는 역할을 하는 컴포넌트이다.
- <Switch> 컴포넌트는 여러 <Route>를 감싸서 그 중 경로가 일치하는 단 하나의 라우터만 렌더링을 시켜주는 역할을 한다. <Switch> 를 사용하지 않으면 매칭되는 모든 요소를 렌더링한다.
- <Route> 컴포넌트는 path 속성을 지정하여 해당 path에 어떤 컴포넌트를 보여줄지 정한다. 아래에서 배울 Link 컴포넌트가 정해주는 URL 경로와 일치하는 경우에만 작동된다.
Link
경로를 연결해주는 역할을 하는 컴포넌트이다. 페이지 전환을 통해 페이지를 새로 불러오지 않고, 애플리케이션을 그대로 유지하여 HTML5의 History API을 이용해 페이지의 주소만 변경해준다.
ReactDOM으로 렌더를 시키게 되면 <Link> 컴포넌트는 <a> 태그로 바뀌는 모습을 볼 수 있다.
참고사항↓
React Router 에서 <a> 태그가 아닌 <Link>를 사용하는 이유가 있나요? <a>태그는 페이지를 전환하는 과정에서 페이지를 불러오기 때문에 다시 처음부터 렌더링을 시킵니다. 즉, 새로고침 현상이 일어나게 되죠. 하지만 <Link> 컴포넌트는 페이지 전환을 방지하는 기능이 내장되어있기 때문에 SPA를 구현할 수 있습니다.
개념을 이해했다면 설치를 진행한다.
앞서 언급했던 npx를 통해서 react tool을 설치했다면,
$ npm i react-router-dom@5.3.0
다음과 같은 npm 명령어를 통해 간단하게 설치할 수 있다.
그 다음
컴포넌트를 꺼내 오기 위한 import 구문도 작성한다.
다음으로 넘어가기 전에 간단한 요구사항을 가진 예제를 해보기로 한다.
### 요구사항
- Create React App 프로젝트를 생성 후, React Router DOM(react-router-dom) 라이브러리를 설치해야 한다.
- React Router DOM의 주요 컴포넌트들을 이용해 주소에 따른 3가지 뷰( Home, MyPage, Dashboard )를 제공해야 한다.
- Home 페이지의 주소 "/"
- MyPage 페이지의 주소 "/mypage"
- Dashboard 페이지의 주소 "/dashboard"
앞서 나온 명령어들을 사용해서 react app과 router dom 설치를 진행한다.
먼저 페이지를 만들어 보도록 하자.
function App () {
return (
{/* Route 를 사용하기 위한 설정을 진행합니다 */}
<BrowserRouter>
<div>
<nav>
<ul>
<li>
Home
</li>
<li>
MyPage
</li>
<li>
Dashboard
</li>
</ul>
</nav>
</div>
</BrowserRouter>
)
}
export default App;
BrowserRouter로 Route 컴포넌트를 이용하기 위한 환경을 세팅한다.
{/* 주소경로와 우리가 아까 만든 3개의 컴포넌트를 연결해줍니다. */}
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/about"> {/* 경로를 설정하고 */}
<MyPage /> {/* 컴포넌트를 연결합니다. */}
</Route>
<Route path="/dashboard">
<Dashboard />
</Route>
</Switch>
</div>
하단부에 Swith와 Route 로 주소 경로와 컴포넌트를 연결한다.
- Route의 path 속성을 이용하여 경로를 작성한다. 경로와 컴포넌트 이름이 동일해야 헷갈리지 않는다. <Route> 태그 안에 연결하고자 하는 컴포넌트를 넣어준다. exact가 없으면 어떻게 될까?
참고사항 ↓
1. Home 컴포넌트 Route 에만 존재하는 exact 라는 것을 보았습니다, 언제 쓰는건가요? React router의 특성상 exact속성이 없으면 해당 경로(예시의 "/")로 시작하는 중복된 <Route> 컴포넌트를 모두 보여줍니다. exact는 주어진 경로와 정확히 일치해야만 설정한 <Route> 컴포넌트를 보여주는 역할을 합니다.
2. exact 속성을 쓰지 않고도 페이지가 전환되는 것을 봤습니다. 왜 그런건가요? <Switch> 를 사용하여 exact 역할을 대신 해주는 경우입니다. 하지만 <Switch>는 순서와 위치가 중요합니다. 위에서 아래로 경로를 하나씩 검사하면서 해당 경로에 해당하는 라우트를 실행시키기 때문입니다. 이런 경우, 비교할 라우트를 더 상단에 작성해야 합니다. 하지만 만약 위의 예제처럼 Home을 위에 둔 상태에서 exact없이 활용한다면 어떻게 될까요? 중복되는 경로로 인해 다른 라우트로의 이동이 불가능한 것을 확인하실 수 있습니다. 이를 해결하는 방법으로 exact를 사용할 수 있습니다.
<li>
<Link to="/">Home</Link>{/* Link 컴포넌트를 이용하여 경로를 연결합니다 */}
</li>
<li>
<Link to="/about">MyPage</Link>
</li>
<li>
<Link to="/dashboard">Dashboard</Link>
</li>
Link의 to 속성을 활용하여 Route 컴포넌트에 설정해준 path 주소를 연결해준다.
적절한 css 수정 후 페이지를 확인하면
다음과 같은 화면을 확인할 수 있다.
advanced 난이도 업로드
## React State & Props
### 목표
- State, Props의 개념에 대해서 이해하고, 실제 프로젝트에 바르게 적용할 수 있다.
- React 함수 컴포넌트(React Function Component)에서 State hook을 이용하여 State를 정의할 수 있다.
- React 컴포넌트(React Component)에 Props를 전달할 수 있다.
- 이벤트 핸들러 함수를 만들고 React에서 이용할 수 있다.
- 실제 웹 애플리케이션의 컴포넌트를 보고 어떤 데이터가 State이고 Props에 적합한지 판단할 수 있다.
- 실제 웹 애플리케이션 개발 시 적합한 State와 Props의 위치를 스스로 정할 수 있다.
- React의 단방향 데이터 흐름(One-way data flow)에 대해 자신의 언어로 설명할 수 있다.
Into
State
살면서 변할 수 있는 값 -> React에서는 컴포넌트의 사용 중 컴포넌트 내부에서 변할 수 있는 값
Props vs. State
props는 외부로부터 전달받은 값
state는 내부에서 변화하는 값
props의 특징
- 컴포넌트의 속성(property)를 의미한다.
- 부모 컴포넌트로부터 전달받은 값이다.
- 어떤 타입의 값도 넣어 전달할 수 있도록 객체의 형태를 가진다.
- 함부로 변경될 수 없는 읽기 전용(read-only) 객체다.
props를 사용하는 방법
- 하위 컴포넌트에 전달하고자 하는 값(data)과 속성을 정의한다.
- props를 이용하여 정의된 값과 속성을 전달한다.
- 전달받은 props를 렌더링한다.
위 단계에 맞추어 컴포넌트를 선언해 보았다.
function Parent() {
return (
<div className="parent">
<h1>I'm the parent</h1>
<Child />
</div>
);
};
function Child() {
return (
<div className="child"></div>
);
};
컴포넌트를 만들었으니 이제 전달하고자 하는 속성을 정의한다. HTML에서 속성과 값을 할당하는 방법과 같다.
<a href="https://www.google.com/">Click me to visit Google</a>
React에서 속성 및 값을 할당하는 방법도 이와 유사하다. 다만, 전달하고자 하는 값을 중괄호 {} 를 이용하여 감싸주면 된다.
<Child attribute={value} />
위 방법을 이용하여 text라는 속성을 선언하고, 이 속성에 "I'm the eldest child"라는 문자열 값을 할당하여 <Child> 컴포넌트에 전달해 본다.
<Child text={"I'm the eldest child"} />
이제 부모 컨포넌트에서 전달한 상기의 문자열을 자식 컴포넌트에서 받아 본다. 함수에 인자를 전달하듯이 React 컴포넌트에 props를 전달하면 되고, 이 props가 필요한 모든 데이터를 가지고 오게 된다.
function Child(props) {
return (
<div className="child"></div>
);
};
마지막으로 이 props를 렌더링하는데, props는 객체라고 하였고, 이 객체의 { key : value }는 부모 컴포넌트에서 정의한
{ attribute : value }의 형태를 가진다. 따라서 JS에서 객체의 value에 접근할 때 dot notation "."을 사용한 것과 동일하게 props의 value또한 dot notation 으로 접근할 수 있다. 아래와 같이 props.text를 JSX에 중괄호와 함께 작성하면 잘 작동한다.
function Child(props) {
return (
<div className="child">
<p>{props.text}</p>
</div>
);
};
props를 전달하는 또 다른 방법으로는 여는 태그와 닫는 태그의 사이에 value를 넣어 전달할 수 있다.
이 경우 props.children 을 이용하면 해당 value에 접근하여 사용할 수 있다.
function Parent() {
return (
<div className="parent">
<h1>I'm the parent</h1>
<Child>I'm the eldest child</Child>
</div>
);
};
function Child(props) {
return (
<div className="child">
<p>{props.children}</p>
</div>
);
};
State hook, useState
useState 사용법
아래의 코드를 분석하면서 사용법을 익혀보도록 한다.
import React, { useState } from "react";
import "./styles.css";
function CheckboxExample() {
const [isChecked, setIsChecked] = useState(false);
const handleChecked = (event) => {
setIsChecked(event.target.checked);
};
return (
<div className="App">
<input type="checkbox" checked={isChecked} onChange={handleChecked} />
<span>{isChecked ? "Checked!!" : "Unchecked"}</span>
</div>
);
}
export default CheckboxExample;
useSetate를 이용하기 위해서는 React로부터 useState를 불러와야 한다.
import { useState } from "react";
이후 useState를 컴포넌트 안에서 호출한다. 호출한다는 것은 "state"라는 변수를 선언하는 것과 같으며,
이 변수의 이름은 아무 이름으로 지어도 된다. 일반적인 변수는 함수가 끝날 때 사라지지만, state 변수는 React에 의해 함수가 끝나도 사라지지 않는다.
문법적으로 보면 아래 예시의 isChecked, setIsChecked는 useState의 리턴값을 구조 분해 할당한 변수이다.
function CheckboxExample() {
// 새로운 state 변수를 선언하고, 여기서는 이것을 isChecked 라 부르겠습니다.
const [isChecked, setIsChecked] = useState(false);
문법 예시
function CheckboxExample() {
// 1번 코드를 풀어쓰면
const [isChecked, setIsChecked] = useState(false); // 1번
//...
// 2번 코드와 같습니다.
const stateHookArray = useState(false); // 2번
const isChecked = stateHookArray[0];
const setIsChecked = stateHookArray[1];
}
구조 분해 할당 예시
useState를 호출하면 배열을 반환하는데, 배열의 0번째 요소는 현재 state 변수이고, 1번째 요소는 이 변수를 갱신할 수 있는 함수다. useState의 인자로 넘겨주는 값은 state의 초기값이다.
const [state 저장 변수, state 갱신 함수] = useState(상태 초기 값);
상기의 수도코드를 실제 코드로 작성해보자.
function CheckboxExample() {
const [isChecked, setIsChecked] = useState(false);
// const [state 저장 변수, state 갱신 함수] = useState(state 초기 값);
- isChecked : state를 저장하는 변수
- setIsChecked : state isChecked 를 변경하는 함수
- useState : state hook
- false : state 초기값
이 state 변수에 저장된 값을 사용하려면 JSX 엘리먼트 안에 직접 불러서 사용하면 된다. 여기서는 isChecked 가 boolean 값을 가지기 때문에 true || false 여부에 따라 다른 결과가 보이도록 삼항연산자를 사용한다.
<span>{isChecked ? "Checked!!" : "Unchecked"}</span>
state 갱신하기
state를 갱신하려면 state 변수를 갱신할 수 있는 함수인 setIsChecked 를 호출한다.
사용자가 체크박스 값을 변경하면 onChange 이벤트가 이벤트 핸들러 함수인 handleChecked 를 호출하고, 이 함수가 setIsChecked 를 호출하게 된다.
setIsChecked 가 호출되면 호출된 결과에 따라 isChecked 변수가 갱신되며, React는 새로운 isChecked 변수를 CheckboxExample 컴포넌트에 넘겨 해당 컴포넌트를 다시 렌더링 한다.
function CheckboxExample() {
const [isChecked, setIsChecked] = useState(false);
const handleChecked = (event) => {
setIsChecked(event.target.checked);
};
return (
<div className="App">
<input type="checkbox" checked={isChecked} onChange={handleChecked} />
<span>{isChecked ? "Checked!!" : "Unchecked"}</span>
</div>
);
}
완성된 체크박스 컴포넌트 예시 ↑
(여기서 input의 checked 속성은 type이 checkbox || radio 인 경우에만 사용가능하고 boolean 결과로 나온다.)
주의점
- React 컴포넌트는 state가 변경되면 새롭게 호출되고, 리렌더링 된다.
- React state는 상태 변경 함수 호출로 변경해야 한다. 강제로 변경을 시도하면 안 됩니다. 상태 변경 함수 사용은 React와 개발자의 약속이기 때문에 지켜야 한다. 강제로 변경을 시도하면, 리렌더링이 되지 않는다거나, state가 제대로 변경되지 않는다.
- 예시 : state.push(1);, state[1] = 2;, state = 'wrong state';
이벤트 처리 Hands-on
React의 이벤트 처리(Event handling) 방식은 DOM의 이벤트 처리 방식과 유사하다. 단 몇 가지 문법 차이가 있다.
- React 에서 이벤트는 소문자 대신 카멜 케이스(camelCase) 를 사용.
- JSX를 사용하여 문자열이 아닌 함수로 이벤트 처리 함수(이벤트 핸들러; Event handler)를 전달.
예를 들어 HTML에서 이벤트 처리 방식이 아래와 같다면,
<button onclick="handleEvent()">Event</button>
React의 이벤트 처리 방식은 아래와 같다.
<button onClick={handleEvent}>Event</button>
React에서 이벤트를 처리하는 기본 방식은 위와 같다. 다음은 자주 사용되는 이벤트 처리에 대한 예시이다.
onChange
<input> <textarea> <select> 와 같은 폼(Form) 엘리먼트는 사용자의 입력값을 제어하는데 사용다. React 에서는 이러한 변경될 수 있는 입력값을 일반적으로 컴포넌트의 state 로 관리하고 업데이트한다. onChange 이벤트가 발생하면 e.target.value 를 통해 이벤트 객체에 담겨있는 input 값을 읽어올 수 있다. 컴포넌트 return 문 안의 input 태그에 value 와 onChange 를 넣어주었다. onChange 는 input 의 텍스트가 바뀔 때 마다 발생하는 이벤트다. 이벤트가 발생하면 handleChange 함수가 작동하며, 이벤트 객체에 담긴 input 값을 setState 를 통해 새로운 state 로 갱신한다.
function NameForm() {
const [name, setName] = useState("");
const handleChange = (e) => {
setName(e.target.value);
}
return (
<div>
<input type="text" value={name} onChange={handleChange}></input>
<h1>{name}</h1>
</div>
)
};
onClick
onClick 이벤트는 말 그대로 사용자가 클릭이라는 행동을 하였을 때 발생하는 이벤트다. 버튼이나 <a> tag 를 통한 링크 이동 등과 같이 주로 사용자의 행동에 따라 애플리케이션이 반응해야 할 때 자주 사용하는 이벤트다. 그럼 위의 onChange 예시에 버튼을 추가하여 버튼 클릭 시 input tag 에 입력한 이름이 alert을 통해 알림창이 팝업되도록 코드를 추가해 보도록 한다.
function NameForm() {
const [name, setName] = useState("");
const handleChange = (e) => {
setName(e.target.value);
}
return (
<div>
<input type="text" value={name} onChange={handleChange}></input>
<button onClick={alert(name)}>Button</button>
<h1>{name}</h1>
</div>
);
};
위와 같이 onClick 이벤트에 alert(name) 함수를 바로 호출하면 컴포넌트가 렌더링될 때 함수 자체가 아닌 함수 호출의 결과가 onClick 에 적용된다. 때문에 버튼을 클릭할 때가 아닌, 컴포넌트가 렌더링될 때에 alert 이 실행되고 따라서 그 결과인 undefined (함수는 리턴값이 없을 때 undefined 를 반환) 가 onClick 에 적용되어 클릭했을 때 아무런 결과도 일어나지 않는다. 따라서 onClick 이벤트에 함수를 전달할 때는 함수를 호출하는 것이 아니라 아래와 같이 리턴문 안에서 함수를 정의하거나 리턴문 외부에서 함수를 정의 후 이벤트에 함수 자체를 전달해야 한다. 단, 두 가지 방법 모두 arrow function 을 사용하여 함수를 정의하여야 해당 컴포넌트가 가진 state에 함수들이 접근할 수 있다.
// 함수 정의하기
return (
<div>
...
<button onClick={() => alert(name)}>Button</button>
...
</div>
);
};
// 함수 자체를 전달하기
const handleClick = () => {
alert(name);
};
return (
<div>
...
<button onClick={handleClick}>Button</button>
...
</div>
);
};
Action item : <select>
select tag 는 사용자가 drop down 목록을 열어 그 중 한가지 옵션을 선택하면, 선택된 옵션이 state 변수에 갱신된다.
import React, { useState } from "react";
import "./styles.css";
function SelectExample() {
const [choice, setChoice] = useState("apple");
const fruits = ["apple", "orange", "pineapple", "strawberry", "grape"];
const options = fruits.map((fruit) => {
return <option value={fruit}>{fruit}</option>;
});
console.log(choice);
const handleFruit = (event) => {
setChoice(event.target.value);
};
return (
<div className="App">
<select onChange={handleFruit}>{options}</select>
<h3>You choose "{choice}"</h3>
</div>
);
}
export default SelectExample;
결과 화면
Action item : Pop up
Pop up 역시 Pop up 의 open 과 close 를 state 를 통해 관리할 수 있다.
'BEB' 카테고리의 다른 글
[Week 4-2] JS/Node 비동기 (0) | 2022.03.28 |
---|---|
[Week 4] 재귀함수 (0) | 2022.03.22 |
[Week3-2] JS/Node 고차함수 (0) | 2022.03.15 |
[Week3] 자료구조 기초 (0) | 2022.03.14 |
[Week2-4] DOM (0) | 2022.03.11 |