1장. 리액트 입문
1. 리액트는 어쩌다 만들어졌을까?
HTML/JS로 만들어진 카운터 예시
// index.html
<h2 id="number">0</h2>
<div>
<button id="increase">+1</button>
<button id="decrease">-1</button>
</div>
// index.js
const number = document.getElementById('number');
const increase = document.getElementById('increase');
const decrease = document.getElementById('decrease');
increase.onclick = () => {
const current = parseInt(number.innerText, 10);
number.innerText = current + 1;
};
decrease.onclick = () => {
const current = parseInt(number.innerText, 10);
number.innerText = current - 1;
};
→ 위의 경우, id를 사용하여 각 DOM을 선택한 뒤, 원하는 이벤트가 발생하면 DOM의 특정 속성을 바꿔주어야 함
단점: 인터랙션이 자주 발생하고, 이에 따라 동적으로 UI를 표현해야 한다면 관리하기 힘들어진다.
그래서, Ember, Backbone, AngularJS 등의 프레임워크가 만들어짐
작동 방식: 자바스크립트의 특정 값이 바뀌면 특정 DOM의 속성이 바뀌도록 연결을 해주어서, 업데이트 하는 작업을 간소화해주는 방식
! 리액트는 다른 발상 !
: 어떠한 상태가 바뀌었을 때, 아예 다 날려버리고 처음부터 모든걸 새로 만들어서 보여주면 어떨까? 라는 아이디어에서 개발이 시작,
그러나 이런 방식은 속도가 굉장히 느림, 그래서 리액트에서는 Virtual DOM을 사용해서 이를 가능하게 함
* virtual DOM
: 가상의 DOM, 메모리에 가상으로 존재하는 DOM, JavaScript 객체이기 때문에 작동 성능이 실제로 브라우저에서 DOM을 보여주는 것보다 속도가 훨씬 빠름
리액트의 작동 방식
: 상태 업데이트 → 업데이트가 필요한 곳의 UI를 Virtual DOM을 통해 렌더링 → 알고리즘을 통해 실제 브라우저에 보여지고 있는 DOM과 비교 → 차이가 있는 곳 감지 → 이를 실제 DOM에 패치
2. 작업환경 준비
다음 항목들을 설치
- Node.js: Webpack, Babel 같은 도구들이 자바스크립트 런타임인 Node.js를 기반으로 만들어져 있기 때문에 이를 사용하기 위해 설치
* Webpack, Babel
: 리액트 프로젝트를 만들게 되면서, 컴포넌트를 여러가지 파일로 분리해서 저장할 것이고, 또 이 컴포넌트는 일반 자바스크립트가 아닌 JSX 라는 문법으로 작성하게 된다. 여러가지 파일을 한개로 결합하기 위해서 Webpack 이라는 도구를 사용하고, JSX 를 비롯한 새로운 자바스크립트 문법들을 사용하기 위해서 Babel 이라는 도구를 사용한다.
Windows 의 경우엔, Node.js 공식 홈페이지 에서 좌측에 나타나는 LTS 버전을 설치
macOS / Linux 의 경우엔, nvm 이라는 도구를 사용하여 Node.js 를 설치하시는 것을 권장
$ curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.8/install.sh | bash
$ nvm install --lts
- Yarn: 조금 개선된 버전의 npm 이라고 생각하면 된다. 더 나은 속도, 더 나은 캐싱 시스템을 사용하기 위해 사용한다.
* npm: Node.js를 설치하게 될 때 같이 딸려오는 패키지 매니저 도구, 프로젝트에서 사용되는 라이브러리를 설치하고 해당 라이브러리들의 버전 관리를 하게 될 때 사용한다.
- 코드 에디터: VSCode, Atom, WebStorm, Sublime 등 여러 가지가 있으므로 좋아하는 에디터를 사용하면 된다.
- Git bash: 윈도우의 경우, Git for Windows를 설치해서 Git Bash 사용하고 윈도우가 아닌 경우 설치하지 않아도 된다.
새 프로젝트 만들어보기
새로운 리액트 프로젝트를 만들어 보자!
// 터미널에서 다음 명령어 실행 (윈도우 사용자는 Git Bash 를 사용)
$ npx create-react-app begin-react
→ begin react 라는 디렉터리가 생기고 그 안에 리액트 프로젝트가 생성된다.
$ cd begin-react
$ yarn start
// yarn 이 없다면 npm start
→ 브라우저에 http://localhost:3000/ 이 열리고, 돌아가는 리액트 아이콘이 보일 것이다.
자동으로 페이지가 열리지 않는다면 브라우저에 주소를 직접 입력하여 들어간다.
VS Code 에서 터미널 띄우기
VS Code 로 해당 디렉터리를 열은 뒤, 상단 메뉴의 View > Terminal 을 연다. (한글 메뉴의 경우 보기 > 터미널)
윈도우 사용자의 경우엔, 위 작업을 하기 전에 VS Code 에서 cmd 대신 Git Bash 를 사용하기 위하여
VS Code 에서 Ctrl + , 를 눌러 설정에 들어간 후,
terminal 을 검색 후 Terminal > External > Windows Exec 부분에 Git Bash 의 경로인 C:\Program Files\Git\bin\bash.exe 를
넣어준다.
Git Bash 를 열었을 때 기본 경로
Git Bash 에서의 ~/ 경로가 어디인지 모른다면 pwd 명령어를 입력해보자.
3. 나의 첫번째 리액트 컴포넌트
src 디렉터리 Hello.js 라는 파일을 다음과 같이 작성해보자!
// Hello.js
import React from 'react'; // 리액트 컴포넌트를 만들 때 이 코드로 리액트를 불러와주어야 함
const Hello = () => <div>안녕하세요</div>;
export default Hello; // Hello 라는 컴포넌트를 내보내겠다는 의미, 이렇게 해주면 다른 컴포넌트에서 불러와서 사용할 수 있다.
→ 리액트 컴포넌트에서는 XML 형식의 값을 반환해줄 수 있는데 이를 JSX 라고 부른다.
이 컴포넌트를 App.js에서 불러와서 사용
// App.js
import React from 'react';
import Hello from './Hello';
const App = () => (
<div>
<Hello />
</div>
);
export default App;
import logo from './logo.svg';
import './App.css';
→ SVG 파일을 불러오고 CSS 적용하는 코드이지만 현재 불필요하므로 생략
컴포넌트는 일종의 UI 조각이며 쉽게 재사용할 수 있다.
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
ReactDOM.render(<App />, document.getElementById('root'));
// id 가 root 인 DOM 을 선택하고 있음
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();
→ ReactDOM.render의 역할: 브라우저에 있는 실제 DOM 내부에 리액트 컴포넌트를 렌더링하겠다는 것을 의미한다.
public/index.html 을 열어보면 내부에
<div id="root"></div>
을 찾아볼 수 있다. 결국, 리액트 컴포넌트가 렌더링 될 때에는, 렌더링된 결과물이 위 div 내부에 렌더링되는 것 이다.
4. JSX의 기본 규칙 알아보기
JSX: 리액트에서 생김새를 정의할 때, 사용하는 문법이다. 얼핏보면 HTML 같이 생겼지만 실제로는 JavaScript 이다.
return <div>안녕하세요</div>;
리액트 컴포넌트 파일에서 XML 형태로 코드를 작성하면 babel 이 JSX 를 JavaScript 로 변환을 해준다.
* Babel
: 자바스크립트의 문법을 확장해주는 도구이다.
아직 지원되지 않는 최신 문법이나, 편의상 사용하거나 실험적인 자바스크립트 문법들을 정식 자바스크립트 형태로 변환해줌으로서 구형 브라우저같은 환경에서도 제대로 실행 할 수 있게 해주는 역할을 한다.
JSX의 기본 규칙
꼭 닫혀야 하는 태그
- 태그는 꼭 닫혀있어야 한다. 그렇지 않으면 오류가 발생한다.
- 태그를 열었으면 꼭, <div></div> 이렇게 닫아주어야 한다.
- HTML 에서는 input 또는 br 태그를 사용 할 때 닫지 않고 사용하기도 하지만 리액트에서는 그렇게 하면 안된다.
- 태그와 태그 사이에 내용이 들어가지 않을 때에는, Self Closing 태그 라는 것을 사용해야 한다
* Self Closing 태그: 열리고, 바로 닫히는 태그를 의미한다.
// App.js
import React from 'react';
import Hello from './Hello';
const App = () => {
return (
<div>
<Hello />
<Hello />
<Hello />
<input />
<br />
</div>
);
}
export default App;
// Hello 컴포넌트를 사용 할 때에도 Self Closing 태그를 사용함
꼭 감싸져야하는 태그
두개 이상의 태그는 무조건 하나의 태그로 감싸져있어야 한다.
import React from 'react';
import Hello from './Hello';
const App = () => {
return (
<Hello />
<div>안녕히계세요.</div>
);
}
→ 오류 발생
// 수정 코드
export default App;
import React from 'react';
import Hello from './Hello';
const App = () => {
return (
<div>
<Hello />
<div>안녕히계세요</div>
</div>
);
}
export default App;
하지만, 이렇게 단순히 감싸기 위하여 불필요한 div 로 감싸는게 별로 좋지 않은 상황도 있다.
예를 들어서 스타일 관련 설정을 하다가 복잡해지게 되는 상황도 올 수 있고, table 관련 태그를 작성 할 때에도 내용을 div 같은걸로 감싸기엔 애매하다. 그럴 땐, 리액트의 Fragment 라는 것을 사용하면 된다.
import React from 'react';
import Hello from './Hello';
const App = () => {
return (
<>
<Hello />
<div>안녕히계세요</div>
</>
);
}
export default App;
→ 태그를 작성 할 때 이름 없이 작성을 하게 되면 Fragment 가 만들어지는데, Fragment 는 브라우저 상에서 따로 별도의 엘리먼트로 나타나지 않는다.
JSX 안에 자바스크립트 값 사용하기
JSX 내부에 자바스크립트 변수를 보여줘야 할 때에는 {} 으로 감싸서 보여준다.
import React from 'react';
import Hello from './Hello';
const App = () => {
const name = 'react';
return (
<>
<Hello />
<div>{name}</div>
</>
);
}
export default App;
style 과 className
- JSX 에서 태그에 style 과 CSS class 를 설정하는 방법은 HTML 에서 설정하는 방법과 다르다.
- 인라인 스타일은 객체 형태로 작성을 해야 하며, background-color 처럼 - 로 구분되어 있는 이름들은 backgroundColor 처럼 camelCase 형태로 네이밍 해주어야 한다.
- CSS class 를 설정 할 때에는 class= 가 아닌 className= 으로 설정을 해주어야 한다.
// App.css
.gray-box {
background: gray;
width: 64px;
height: 64px;
}
// App.js
import React from 'react';
import Hello from './Hello';
import './App.css';
const App = () => {
const name = 'react';
const style = {
backgroundColor: 'black',
color: 'aqua',
fontSize: 24, // 기본 단위 px
padding: '1rem' // 다른 단위 사용 시 문자열로 설정
}
return (
<>
<Hello />
<div style={style}>{name}</div>
<div className="gray-box"></div>
</>
);
}
export default App;
주석
- JSX 내부의 주석은 {/* 이런 형태로 */} 작성한다.
- 추가적으로, 열리는 태그 내부에서는 // 이런 형태로도 주석 작성이 가능하다.
import React from 'react';
import Hello from './Hello';
import './App.css';
const App = () => {
const name = 'react';
const style = {
backgroundColor: 'black',
color: 'aqua',
fontSize: 24, // 기본 단위 px
padding: '1rem' // 다른 단위 사용 시 문자열로 설정
}
return (
<>
{/* 주석은 화면에 보이지 않습니다 */}
/* 중괄호로 감싸지 않으면 화면에 보입니다 */
<Hello
// 열리는 태그 내부에서는 이렇게 주석을 작성 할 수 있습니다.
/>
<div style={style}>{name}</div>
<div className="gray-box"></div>
</>
);
}
export default App;
5. props 를 통해 컴포넌트에게 값 전달하기
props 는 properties 의 줄임말로 우리가 어떠한 값을 컴포넌트에게 전달해줘야 할 때, props 를 사용한다.
props 의 기본 사용법
예를 들어서, App 컴포넌트에서 Hello 컴포넌트를 사용 할 때 name 이라는 값을 전달해주고 싶다고 가정해보자!
// App.js
import React from 'react';
import Hello from './Hello';
const App = () => <Hello name="react" />;
export default App;
// Hello.js
import React from 'react';
const Hello = (props) => <div>안녕하세요 {props.name}</div>;
export default Hello;
컴포넌트에게 전달되는 props 는 파라미터를 통하여 조회 할 수 있다.
props 는 객체 형태로 전달되며, 만약 name값을 조회하고 싶다면 props.name 을 조회하면 된다.
여러개의 props, 비구조화 할당
Hello 컴포넌트에 또 다른 props 를 전달해보자!
// App.js
import React from 'react';
import Hello from './Hello';
const App = () => <Hello name="react" color="red"/>; {/* color 라는 값 설정 */}
export default App;
다음으로는 Hello 컴포넌트에서 color 값을 조회해서 폰트의 색상으로 설정을 해보자!
// Hello.js
import React from 'react';
const Hello = (props) => <div style={{ color: props.color }}>안녕하세요 {props.name}</div>;
export default Hello;
props 내부의 값을 조회 할 때마다 props. 를 입력하고 있는데,
함수의 파라미터에서 비구조화 할당 (혹은 구조 분해) 문법을 사용하면 조금 더 코드를 간결하게 작성 할 수 있다.
// Hello.js
import React from 'react';
const Hello = ({ color, name }) => <div style={{ color }}>안녕하세요 {name}</div>;
export default Hello;
defaultProps 로 기본값 설정
컴포넌트에 props 를 지정하지 않았을 때 기본적으로 사용 할 값을 설정하고 싶다면 컴포넌트에 defaultProps 라는 값을 설정하면 된다.
// Hello.js
import React from 'react';
const Hello = ({ color, name }) => <div style={{ color }}>안녕하세요 {name}</div>;
}
Hello.defaultProps = {
name: '이름없음'
}
export default Hello;
App 에서 name 이 없는 Hello 컴포넌트를 렌더링해보자!
// App.js
import React from 'react';
import Hello from './Hello';
const App () => {
return (
<>
<Hello name="react" color="red"/>
<Hello color="pink"/>
</>
);
}
export default App;
props.children
컴포넌트 태그 사이에 넣은 값을 조회하고 싶을 땐, props.children 을 조회하면 된다.
// Wrapper.js
import React from 'react';
const Wrapper () => {
const style = {
border: '2px solid black',
padding: '16px',
};
return (
<div style={style}>
</div>
)
}
export default Wrapper;
이 컴포넌트를 App 에서 사용해보자!
// App.js
import React from 'react';
import Hello from './Hello';
import Wrapper from './Wrapper';
const App = () => {
return (
<Wrapper>
<Hello name="react" color="red"/>
<Hello color="pink"/>
</Wrapper>
);
}
export default App;
→ 브라우저를 확인하면 다음과 같이 Hello 컴포넌트들은 보여지지 않을 것이다.
내부의 내용이 보여지게 하기 위해서는 Wrapper 에서 props.children 을 렌더링해주어야 한다.
// Wrapper.js
import React from 'react';
const Wrapper = ({ children }) => {
const style = {
border: '2px solid black',
padding: '16px',
};
return (
<div style={style}>
{children}
</div>
)
}
export default Wrapper;
6. 조건부 렌더링
조건부 렌더링: 특정 조건에 따라 다른 결과물을 렌더링 하는 것을 의미한다.
// App.js
import React from 'react';
import Hello from './Hello';
import Wrapper from './Wrapper';
const App = () => {
return (
<Wrapper>
<Hello name="react" color="red" isSpecial={true}/>
{/* isSpecial 이라는 props 를 설정 */}
{/* true 는 자바스크립트 값이기 때문에 중괄호로 감싸줌 */}
<Hello color="pink" />
</Wrapper>
)
}
export default App;
Hello 컴포넌트에서는 isSpecial 이 true 이냐 false 이냐에 따라서 컴포넌트의 좌측에 * 표시를 보여줘보자!
이를 처리하는 가장 기본적인 방법은, 삼항연산자를 사용하는 것이다.
// Hello.js
import React from 'react';
const Hello = ({ color, name, isSpecial }) => {
return (
<div style={{ color }}>
{ isSpecial ? <b>*</b> : null }
{/* isSpecial 값이 true 라면 <b>*</b> 를, 그렇지 않다면 null 을 보여주도록 함 */}
안녕하세요 {name}
</div>
);
}
Hello.defaultProps = {
name: '이름없음'
}
export default Hello;
* JSX 에서 null, false, undefined 를 렌더링하게 된다면 아무것도 나타나지 않게 된다.
삼항연산자를 사용한 조건부 렌더링은 주로 특정 조건에 따라 보여줘야 하는 내용이 다를 때 사용한다.
지금은 내용이 달라지는게 아니라, 단순히 특정 조건이 true 이면 보여주고, 그렇지 않다면 숨겨주고 있는데,
이러한 상황에서는 && 연산자를 사용해서 처리하는 것이 더 간편하다.
// Hello.js
import React from 'react';
const Hello = ({ color, name, isSpecial }) => {
return (
<div style={{ color }}>
{isSpecial && <b>*</b>}
{/* isSpecial 이 false 일땐 false 이고, isSpecial이 true 일 땐 <b>*</b> 가 됨 *}
안녕하세요 {name}
</div>
);
}
Hello.defaultProps = {
name: '이름없음'
}
export default Hello;
props 값 설정을 생략하면 ={true}
컴포넌트의 props 값을 설정하게 될 때 만약 props 이름만 작성하고 값 설정을 생략한다면, 이를 true 로 설정한 것으로 간주한다.
// App.js
import React from 'react';
import Hello from './Hello';
import Wrapper from './Wrapper';
const App = () => {
return (
<Wrapper>
<Hello name="react" color="red" isSpecial />
<Hello color="pink"/>
</Wrapper>
);
}
export default App;
→ isSpecial 이름만 넣어주면 isSpecial={true} 와 동일한 의미
7. useState 를 통해 컴포넌트에서 바뀌는 값 관리하기
컴포넌트에서 보여줘야 하는 내용이 사용자 인터랙션에 따라 바뀌어야 할 때 어떻게 구현할 수 있는지에 대하여 알아보자!
리액트 16.8 에서 Hooks 라는 기능이 도입되면서 함수형 컴포넌트에서도 상태를 관리할 수 있게 되었다.
이번에는 useState 라는 함수를 사용해보게 되는데, 이게 바로 리액트의 Hooks 중 하나이다.
버튼을 누르면 숫자가 바뀌는 Counter 컴포넌트를 만들어보자!
// Counter.js
import React from 'react';
const Counter = () => {
return (
<div>
<h1>0</h1>
<button>+1</button>
<button>-1</button>
</div>
);
}
export default Counter;
// App.js
import React from 'react';
import Counter from './Counter';
const App = () => <Counter />;
export default App;
이벤트 설정
Counter 에서 버튼이 클릭되는 이벤트가 발생 했을 때, 특정 함수가 호출되도록 설정을 해보자!
// Counter.js
import React from 'react';
const Counter = () => {
const onIncrease = () => {
console.log('+1')
}
const onDecrease = () => {
console.log('-1');
}
return (
<div>
<h1>0</h1>
<button onClick={onIncrease}>+1</button>
<button onClick={onDecrease}>-1</button>
</div>
);
}
export default Counter;
함수를 만들고, button 의 onClick 으로 각 함수를 연결해준다.
리액트에서 엘리먼트에 이벤트를 설정해줄때에는 on이벤트이름={실행하고싶은함수} 형태로 설정해주어야 한다.
! 주의 ! 함수형태를 넣어주어야 하지, 함수를 다음과 같이 실행하면 안됨
onClick={onIncrease()}
// 이 경우 렌더링되는 시점에서 함수가 호출됨
동적인 값 끼얹기 , useState
컴포넌트에서 동적인 값을 상태(state)라고 부른다. 리액트의 useState 라는 함수를 사용하면 컴포넌트에서 상태를 관리할 수 있다.
// Counter.js
import React, { useState } from 'react'; // 리액트 패키지에서 useState 라는 함수를 불러와줌
const Counter = () => {
const [number, setNumber] = useState(0);
// useState 를 사용 할 때에는 상태의 기본값을 파라미터로 넣어서 호출해줌
// 함수 호출 결과 배열이 반환됨, 첫번째 원소는 현재 상태이고 두번째 원소는 Setter 함수임
const onIncrease = () => {
setNumber(number + 1);
}
const onDecrease = () => {
setNumber(number - 1);
}
// Setter 함수는 파라미터로 전달 받은 값을 최신 상태로 설정해줌
return (
<div>
<h1>{number}</h1>
<button onClick={onIncrease}>+1</button>
<button onClick={onDecrease}>-1</button>
</div>
);
}
export default Counter;
함수형 업데이트
지금은 Setter 함수를 사용 할 때, 업데이트 하고 싶은 새로운 값을 파라미터로 넣어주고 있는데,
그 대신에 기존 값을 어떻게 업데이트 할 지에 대한 함수를 등록하는 방식으로도 값을 업데이트 할 수 있다.
// Counter.js
import React, { useState } from 'react';
const Counter = () => {
const [number, setNumber] = useState(0);
const onIncrease = () => {
setNumber(prevNumber => prevNumber + 1);
}
const onDecrease = () => {
setNumber(prevNumber => prevNumber - 1);
}
return (
<div>
<h1>{number}</h1>
<button onClick={onIncrease}>+1</button>
<button onClick={onDecrease}>-1</button>
</div>
);
}
export default Counter;
→ 함수형 업데이트는 주로 나중에 컴포넌트를 최적화를 하게 될 때 사용하게 된다. (왜 최적화랑 관련이 있는지는 나중에 알아보자...)
8. input 상태 관리하기
이번에는 리액트에서 사용자가 입력 할 수 있는 input 태그의 상태를 관리하는 방법을 알아보자!
// InputSample.js
import React from 'react';
const InputSample = () => {
return (
<div>
<input />
<button>초기화</button>
<div>
<b>값: </b>
</div>
</div>
);
}
export default InputSample;
// App.js
import React from 'react';
import InputSample from './InputSample';
const App = () => <InputSample />;
export default App;
input 에 입력하는 값이 하단에 나타나게 하고, 초기화 버튼을 누르면 input 이 값이 비워지도록 구현을 해보자!
// InputSample.js
import React, { useState } from 'react';
const InputSample = () => {
const [text, setText] = useState('');
const onChange = (e) => {
setText(e.target.value);
};
// e.target 은 이벤트가 발생한 DOM 인 input DOM 을 가르키게 됨
// e.target.value 를 조회하면 현재 input 에 입력한 값이 무엇인지 알 수 있음
const onReset = () => {
setText('');
};
return (
<div>
<input onChange={onChange} value={text} />
<button onClick={onReset}>초기화</button>
<div>
<b>값: {text}</b>
</div>
</div>
);
}
export default InputSample;
* input 의 상태를 관리할 때에는 input 태그의 value 값도 설정해주는 것이 중요하다. 그렇게 해야, 상태가 바뀌었을때 input 의 내용도 업데이트 된다.
9. 여러개의 input 상태 관리하기
이번에는 input 이 여러개일때는 어떻게 관리해야 하는지 알아보자!
// InputSample.js
import React, { useState } from 'react';
const InputSample = () => {
const onChange = (e) => {
};
const onReset = () => {
};
return (
<div>
<input placeholder="이름" />
<input placeholder="닉네임" />
{/* input 이 비어져있을 때 인풋에 대한 설명을 보여주는 placeholder 값 설정 */}
<button onClick={onReset}>초기화</button>
<div>
<b>값: </b>
이름 (닉네임)
</div>
</div>
);
}
export default InputSample;
input 의 개수가 여러개일 때, useState 를 여러번 사용하고 onChange 도 여러개 만들어서 구현할 수 있지만 좋은 방법은 아니다.
더 좋은 방법은, input 에 name 을 설정하고 이벤트가 발생했을 때 이 값을 참조하는 것
그리고, useState 에서는 문자열이 아니라 객체 형태의 상태를 관리해주어야 합니다.
// InputSample.js
import React, { useState } from 'react';
const InputSample = () => {
const [inputs, setInputs] = useState({
name: '',
nickname: ''
});
const { name, nickname } = inputs; // 비구조화 할당을 통해 값 추출
const onChange = (e) => {
const { value, name } = e.target; // 우선 e.target 에서 name 과 value 를 추출
setInputs({
...inputs, // 기존의 input 객체를 복사한 뒤
[name]: value // name 키를 가진 값을 value 로 설정
});
};
const onReset = () => {
setInputs({
name: '',
nickname: '',
})
};
return (
<div>
<input name="name" placeholder="이름" onChange={onChange} value={name} />
<input name="nickname" placeholder="닉네임" onChange={onChange} value={nickname}/>
<button onClick={onReset}>초기화</button>
<div>
<b>값: </b>
{name} ({nickname})
</div>
</div>
);
}
export default InputSample;
리액트 상태에서 객체를 수정해야 할 때에는,
inputs[name] = value;
// 위와 같이 기존 상태를 직접 수정하게 되면, 값을 바꿔도 리렌더링이 되지 않는다.
이런식으로 직접 수정하면 안된다. 그 대신에, 새로운 객체를 만들어서 새로운 객체에 변화를 주고, 이를 상태로 사용해주어야 한다.
setInputs({
...inputs,
[name]: value
});
* spread 문법 (... 문법): 객체의 내용을 모두 "펼쳐서" 기존 객체를 복사해준다.
이러한 작업을, "불변성을 지킨다" 라고 부른다. 불변성을 지켜주어야만 리액트 컴포넌트에서 상태가 업데이트가 됐음을 감지 할 수 있고 이에 따라 필요한 리렌더링이 진행된다.
'WINK-(Web & App) > React.js 스터디' 카테고리의 다른 글
[2024 여름방학 React.js 스터디] 김태일 #3주차 "리액트 입문" (0) | 2024.07.26 |
---|---|
[2024 여름방학 React.js 스터디] 김민서 #3주차 (0) | 2024.07.26 |
[2024 여름방학 React.js 스터디] 백채린 #2주차 섹션 8~9 (0) | 2024.07.19 |
[2024 여름방학 React.js 스터디] 이종윤 #2주차 (0) | 2024.07.19 |
[2024 여름방학 React.js 스터디] 김민서 #2주차 (0) | 2024.07.19 |