리액트의 기본 기능 다루기

로이·2024년 4월 22일

컴포넌트

실습 환경 설정하기 (CRA 사용)

리액트 앱 만들기

터미널에서

> npx create-react-app .

사용하지 않는 파일 삭제하기

아래 파일 삭제

src/App.test.js
src/logo.svg
src/reportWebVitals.js // 성능 측정 용도
src/setupTest.js

사용하지 않을 코드 삭제하기

src/index.js 와 src/App.js 에서 불필요한 코드를 제거하고 앱 실행

> npm run start
// index.js

import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);
// App.js

import "./App.css";

function App() {
	return <div className="App"></div>
}
export default App;

실습 환경 설정하기 (VITE 사용)

리액트 앱 만들기

터미널에서 하되, 만들려는 디렉토리의 상위 폴더에서 실행해야 함

> npm create vite@latest

? Project name: > [프로젝트 명] 입력

? Select a framework: > React 선택

? Select a variant: > Javascript 선택

> 프로젝트 폴더로 이동

> npm i (install)

사용하지 않는 파일 삭제하기

아래 파일 삭제

public/vite.svg
src/assets/react.svg

사용하지 않을 코드 삭제하기

src/App.jsx, src/App.css, src/index.css, src/main.jsx 에서 불필요한 코드를 제거하고 앱 실행

> npm run dev

eslint 옵션 추가하기 (필수 아님)

.eslintrc.cjs 파일에서 rules에 아래 옵션 추가

"no-unused-vars": "off", "react/prop-types": "off"
// main.jsx

import ReactDOM from "react-dom/client";
import App from "./App.jsx";
import "./index.css";

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
// App.jsx

import "./App.css";

function App() {
  return (
    <>
    </>
  );
}

export default App;

첫 컴포넌트 만들기

리액트 컴포넌트는 주로 자바스크립트의 클래스나 함수를 이용해 만드나, 클래스로 컴포넌트를 만드는 방식은 단점이 많아 함수로 컴포넌트를 만드는 방식을 권장

함수 컴포넌트 만들기

// App.js

import "./App.css";

const Header = () => {
	return (
    	<header>
        	<h1>header</h1>
        </header>
    );
}

function App() {
	return <div className="App"></div>
}
export default App;
! 함수 컴포넌트의 이름 첫 글자는 항상 영어 대문자이어야 하며, 이는 리액트 컴포넌트를 HTML 태그와 구분하기 위해서임

컴포넌트를 페이지에 렌더링하기

// App.js

import "./App.css";

const Header = () => {
	(...)
}

function App() {
	return (
    	<div className="App">
        	<Header />
        </div>
    );
}
export default App;

컴포넌트의 계층 구조

부모의 return 문에 자식을 포함하는 행위를 '자식 컴포넌트를 배치한다'라고 표현하며, 리액트에서 컴포넌트를 페이지에 렌더링하려면, App의 자식으로 배치하거나 이미 자식으로 배치된 컴포넌트의 또 다른 자식으로 배치해야 함

컴포넌트별로 파일 분리하기

리액트에서는 보통 하나의 파일에 하나의 컴포넌트를 만듦
// component/Header.js

function Header() {
	return (
    	<header>
        	<h1>header</h1>
        </header>
    );
}
export default Header;
// component/Body.js

function Body() {
	return (
    	<header>
        	<h1>body</h1>
        </header>
    );
}
export default Body;
// component/Footer.js

function Footer() {
	return (
    	<header>
        	<h1>footer</h1>
        </header>
    );
}
export default Footer;
// App.js

import "./App.css";
import Header from "./component/Header";
import Body from "./component/Body";
import Footer from "./component/Footer";

function App() {
	return (
    	<div className="App">
        	<Header />
        	<Body />
        	<Footer />
        </div>
    );
}
export default App;

JSX

JSX란?

자바스크립트와 HTML 태그를 섞어 사용하는 문법을 JSX(자바스크립트 XML)라고 하며, 이는 자바스크립트의 확장 문법이되 공식 자바스크립트 문법은 아니나, 리액트에서도 적극 권장함

JSX와 자바스크립트 표현식

자바스크립트 표현식이라는 걸 표현하기 위해 중괄호 ({ })를 사용
function Body() {
	const number = 1;
    
    return (
    	<div>
        	<h1>body</h1>
            <h2>{number}</h2>
        </div>
    );
}
export default Body;

산술 표현식

산술 표현식이란 숫자로 표현되는 식
function Body() {
	const numA = 1;
    const nunB = 2;
    
    return (
    	<div>
        	<h1>body</h1>
            <h2>{numA + numB}</h2>
        </div>
    );
}
export default Body;

문자열 표현식

문자열 표현식이란 문자열 또는 문자열로 평가되는 식
function Body() {
	const strA = "안녕";
    const strB = "리액트";
    
    return (
    	<div>
        	<h1>body</h1>
            <h2>{strA + strB}</h2>
        </div>
    );
}
export default Body;

논리 표현식

논리 표현식이란 참이나 거짓으로 평가되는 식
function Body() {
	const boolA = true;
    const boolB = false;
    
    return (
    	<div>
        	<h1>body</h1>
            <h2>{boolA || boolB}</h2>
        </div>
    );
}
export default Body;

// 불리언 값은 페이지에 렌더링 되지 않으므로, 문자열로 바꿔서 렌더링 가능

(...)
	<h2>{String(boolA || boolB)}</h2>
(...)

사용할 수 없는 값

원시 자료형에 해당하는 숫자, 문자열, 불리언, null, undefined를 제외한 값을 사용하면 오류 발생
function Body() {
	const objA = {
    	a: 1,
        b: 2,
    };
    
    return (
    	<div>
        	<h1>body</h1>
            <h2>{objA}</h2>
        </div>
    );
}
export default Body;

// 콘솔에서 "Object are not valid as a React Child" 에러 메시지 출력
왜 객체 같은걸 사용하면 안되나요? 그냥 외우는것인지 논리적인 이유가 있는 것인지?

JSX 문법에서 지켜야 할 것들

닫힘 규칙

JSX의 모든 태그는 여는 태그가 있으면 반드시 닫는 태그도 있어야 하는 규칙이며, 많이 사용하는 HTML 태그 중 <img>, <input>은 닫힘 태그 없이도 사용할 수 있으나 JSX에서는 허용하지 않음

최상위 태그 규칙

JSX가 반환하는 모든 태그는 반드시 최상위 태그로 감싸야 함
function Body() {
	return (
    	<div>div 1</div>
    	<div>div 2</div>
    );
}
export default Body;

// error 발생
// <React.Fragment> 태그 사용 가능

import React from "react";	// <React.Fragment> 컴포넌트는 react 라이브러리에서 불러와야 함

function Body() {
	return (
    	<React.Fragment>
        	<div>div 1</div>
            <div>div 2</div>
        </React.Fragment>
    );
}
export default Body;
// <> 빈 태그 사용 가능

function Body() {
	return (
    	<>
        	<div>div 1</div>
            <div>div 2</div>
        </>
    );
}
export default Body;

조건부 렌더링

리액트 컴포넌트가 조건식의 결과에 따라 각기 다른 값을 페이지에 렌더링하는 것

삼항 연산자를 활용한 조건부 렌더링

코드가 매우 간결하지만, 자주 사용할 경우 가독성을 해칠 우려가 있고, 다중 조건을 작성하기 힘듦
import React from "react";

function Body() {
	const num = 19;
    
    return (
    	<>
        	<h2>
            	{num}은(는) {num % 2 === 0 ? "짝수" : "홀수"}입니다.
            </h2>
        </>
    );
}
export default Body;

조건문을 이용한 조건부 렌더링

가독성은 좋으나, 기본적으로 작성해야 할 코드가 많고 중복 코드가 발생할 우려도 있음
import React from "react";

function Body() {
	const num = 200;
    
    if (num % 2 === 0) {
    	return <div>{num}은(는) 짝수입니다</div>;
    } else {
    	return <div>{num}은(는) 홀수입니다</div>;
    }
}
export default Body;

JSX 스타일링

스타일링이란 CSS와 같은 스타일 규칙을 이용해 요소의 크기, 색상 등을 결정하는 일

인라인 스타일링

JSX 문법 중 하나로 HTML의 style 속성을 이용해 직접 스타일을 정의하는 방법으로 아래와 같은 문법으로 작성

style={ {스타일 규칙들} }

- 문자열로 작성하는 HTML의 인라인 스타일링과는 달리, JSX의 인라인 스타일링은 객체를 생성한 다음 각각의 스타일을 프로퍼티 형식으로 작성
- background-color처럼 CSS에서 속성을 표시할 때 사용하는 스네이크 케이스 표기법 대신 backgroundColor와 같이 카멜 표기법으로 작성

장점

하나의 파일 안에서 UI 표현을 위한 HTML과 스타일을 위한 CSS 규칙을 함께 작성할 수 있음

단점

페이지가 스타일을 계산할 때 불필요한 연산을 수행할 가능성이 있고, 스타일 규칙이 많으면 코드가 복잡해져 가독성이 떨어짐
function Body() {
	return (
    	<div style={{ backgroundColor: "red", color: "blue" }}>
        	<h1>body</h1>
        </div>
    );
}
export default Body;

스타일 파일 분리

HTML에서 스타일을 정의한 CSS 파일을 따로 작성해서 사용하듯이, 리액트의 JSX도 마찬가지로 별도의 CSS 스타일 파일을 만들고 이를 불러와 스타일을 적용할 수 있음

- HTML 문법과는 달리 요소의 이름을 지정할 때 class 선택자가 아닌 className을 사용 (class가 자바스크립트의 예약어이기 때문)
// component/Body.css

.body {
	background-color: green;
    color: blue;
}
// component/Body.js

import "./Body.css";

function Body() {
	return (
    	<div className="body">
        	<h1>body</h1>
        </div>
    );
}
export default Body;

컴포넌트에 값 전달하기

Props란?

리액트에서는 내용은 다르지만 구조가 같고 재사용하려는 요소를 주로 컴포넌트로 만들고, 컴포넌트의 공통 기능이 아닌 세부 기능을 표현하기 위해 컴포넌트에 값을 전달하는 경우에는 컴포넌트의 속성을 지정하는 경우가 대부분임

즉, 부모가 자식 컴포넌트에 단일 객체 형태로 값을 전달할 수 있으며, 이 객체를 Props(Properties = 속성) 라고 함

Props로 값 전달하기

Props는 부모만이 자식 컴포넌트에 전달할 수 있으며, 그 역은 성립하지 않음

Props로 하나의 값 전달하기

부모에서는 Props를 전달하려는 자식 컴포넌트 태그에서 이름={값} 형식으로 작성
// App.js

(...)

function App() {
	const name = "이정환";
    
    return (
    	<div className="App">
        	<Header />
            <Body name={name} />
            <Footer />
        </div>
    );
}
export default App;
자식에서는 부모 컴포넌트에서 전달된 객체 Props는 함수의 매개변수 형태로 저장됨
// component/Body.js

function Body(props) {
	console.log(props);
    return <div className="body">{props.name}</div>;
}
export default Body;

Props로 여러 개의 값 전달하기

// App.js

(...)

function App() {
	const name = "이정환";
    
    return (
    	<div className="App">
        	<Header />
            <Body name={name} location={"부천시"} />
            <Footer />
        </div>
    );
}
export default App;
// component/Body.js

function Body(props) {
	console.log(props);
    return (
    	<div className="body">
    		{props.name}은 {props.location}에 거주합니다
    	</div>;
    );
}
export default Body;

구조 분해 할당으로 여러 개의 값 사용하기

Props로 전달된 값이 많으면, 이 값을 사용할 때마다 객체의 점 표기법을 사용해야해서 불편하므로, 구조 분해 할당하여 간편하게 사용 가능
// component/Body.js

function Body(props) {
	const { name, location } = props;
    console.log(name, location);
    
 	return (
    	<div className="body">
        	{name}은 {location}에 거주합니다
        </div>
    );
}
export default Body;
Body 컴포넌트의 매개변수에서 구조 분해 할당하면 더 간결한 코드를 작성할 수 있음
// component/Body.js

function Body({ name, location }) {
    console.log(name, location);
    
 	return (
    	<div className="body">
        	{name}은 {location}에 거주합니다
        </div>
    );
}
export default Body;

스프레드 연산자로 여러 개의 값 쉽게 전달하기

반대로, 부모 컴포넌트에서 Props로 전달할 값이 많으면, 값을 일일이 명시해야 하므로 불편할 뿐만 아니라 가독성도 떨어지므로, App에서 Body 컴포넌트에 전달할 값을 객체로 만든 다음, 스프레드 연산자를 이용해 객체의 프로퍼티를 각각 Props 값으로 전달
// App.js

(...)

function App() {
	const BodyProps = {
    	name: "이정환",
        location: "부천시",
    };
    
    return (
    	<div className="App">
        	<Header />
            <Body {...BodyProps} />
            <Footer />
        </div>
    );
}
export default App;

기본값 설정하기

App 컴포넌트에서 Props의 값 중 favorList를 전달하지 않은 경우, Body 컴포넌트의 배열 favorList의 값은 undefined가 되고, 해당 배열의 length 프로퍼티로 접근하면 Error 발생

Uncaught TypeError: Cannot read properties of undefined (reading 'length')
// App.js

(...)

function App() {
	const BodyProps = {
    	name: "이정환",
        location: "부천시",
        // favorList: ["파스타", "빵", "떡볶이"],
    };
    
    return (
    	<div className="App">
        	<Header />
            <Body {...BodyProps} />
            <Footer />
        </div>
    );
}
export default App;
// component/Body.js

function Body({ name, location, favorList }) {
    console.log(name, location, favorList);
    
 	return (
    	<div className="body">
        	{name}은 {location}에 거주합니다.
            <br />
            {favorList.length}개의 음식을 좋아합니다.
        </div>
    );
}
export default Body;
이런 경우, defaultProps를 이용하면 컴포넌트가 받을 Props의 기본값을 미리 설정할 수 있기 때문에 오류를 미연에 방지할 수 있음
// component/Body.js

function Body({ name, location, favorList }) {
    console.log(name, location, favorList);
    
 	return (
    	<div className="body">
        	{name}은 {location}에 거주합니다.
            <br />
            {favorList.length}개의 음식을 좋아합니다.
        </div>
    );
}

Body.defaultProps = {
	favorList: [],
};
export default Body;
! 실무에서는 백엔드 서버가 제공하는 데이터를 Props로 주고받는 경우가 많기 때문에, 예상치 못한 서버 오류로 인해 정상적인 값을 받지 못하면 오류가 발생함

Props로 컴포넌트 전달하기

리액트에서는 자식 컴포넌트에 또 다른 컴포넌트를 배치하면, 배치된 컴포넌트는 자동으로 Props의 children 프로퍼티에 저장되어 전달되므로, Props로 자바스크립트 값뿐만 아니라 컴포넌트도 전달할 수 있게 됨
// component/Body.js

function Body({ children }) {
	console.log(children);
    return <div className="body">{children}</div>
}
export default Body;

// children 프로퍼티로 전달되는 자식 컴포넌트는 값으로 취급되어, JSX의 표현식으로 사용 가능
! JSX에서는 자바스크립트 표현식이 객체를 평가할 경우 오류가 발생하지만, children 객체는 리액트 컴포넌트를 표현한 것이므로 오류가 발생하지 않음

이벤트 처리하기

이벤트란 웹 페이지에서 일어나는 사용자의 행위로서, 버튼 클릭, 페이지 스크롤, 새로고침 등이 이런 행위에 해당함

이벤트 핸들링과 이벤트 핸들러

이벤트 핸들링이란, 이벤트가 발생하면 특정 코드가 동작하도록 만드는 작업
// HTML과 자바스크립트로 이벤트를 핸들링 하는 예

<script>
	function handleOnClick() {
    	alert("button clicked!");
    }
</script>

<button onclick="handleOnClick">
	Click Me!
</button>

리액트의 이벤트 핸들링

- 이벤트 핸들러 표기에서, HTML은 onclick이지만 리액트는 카멜 케이스 문법에 따라 onClick으로 표기
- Props로 전달할 값을 지정할 때처럼 onClick={} 문법으로 이벤트 핸들러 설정
- 이벤트 핸들러 설정할 때는 함수 호출의 결괏값을 전달하는 것이 아니라, 콜백 함수처럼 함수 그 자체를 전달
// 리액트로 이벤트를 핸들링 하는 예

function Body() {
    function handleOnClick() {
        alert("button clicked!");
    }
	return (
    	<div className="body">
        	<button onClick={handleOnClick}>Click Me!</button>
        </div>
    );
}
export default Body;

이벤트 객체 사용하기

이벤트 객체 e의 target 프로퍼티에는 이벤트가 발생한 페이지의 요소(여기서는 버튼)가 저장되므로, A 버튼을 클릭하면 e.target에는 A 버튼이 저장되고, B 버튼을 클릭하면 e.target에는 B 버튼이 저장됨
function Body() {
	function handlOnClick(e) {
    	console.log(e.target.name);
    }
    return (
    	<div className="body">
        	<button name="A 버튼" onClick={handleOnClick}>
            	A 버튼
            </button>
            <button name="B 버튼" onClick={handleOnClick}>
            	B 버튼
            </button>
        </div>
    );
}
export default Body;

컴포넌트와 상태

State를 이용해서, 사용자의 행위나 시간 변동에 따라 값이 변하는 동적인 리액트 컴포넌트를 만들 수 있음

State 이해하기

전구의 상태가 상태 변화에 따라 점등 또는 소등으로 변하는 것처럼 리액트 컴포넌트 또한 State 값에 따라 다른 결과를 렌더링 함

State의 기본 사용법

useState로 State 생성하기

useState로 State를 생성하며, 2개의 요소가 담긴 배열을 반환함

const [light, setLight] = useState('off');

- light: 'State 변수'라고 하며 현재 상태의 값을 저장하고 있는 변수
- setLight: 'set 함수'라고 하며 State 변수의 값을 업데이트하는 함수
- off: State 변수 light의 초깃값
import {useState} from "react";

function Body() {
	const [count, setCount] = useState(0);
    return (
    	<div>
        	<h2>{count}</h2>
        </div>
    );
}
export default Body;

set 함수로 State 값 변경하기

리액트 컴포넌트는 자신이 관리하는 State 값이 변하면 다시 호출되므로, 자동으로 리렌더(=리렌더링) 됨
// '+' button을 클릭하면 count 값이 1씩 증가하는 예제

import { useState} from "react";

function Body() {
	const [count, setCount] = useState(0);
    const onIncrease = () => {
    	setCount(count + 1);
    };
    return (
    	<div>
        	<h2>{count}</h2>
            <button onClick={onIncrease}>+</button>
        </div>
    );
}
export default Body;
위 예제에서는 특정한 값이 필요없어서 e.target.value 를 사용하지 않은 것인지?

State로 사용자 입력 관리하기

HTML에서 입력 폼을 만드는 태그로는 다양한 형ㅎ식의 정보를 입력할 수 있는 <input> 태그, 여러 옵션에서 하나를 선택하도록 드롭다운(DropDown) 목록을 보여주는 <select> 태그, 여러 줄의 텍스트를 입력할 수 있는 <textarea> 태그 등이 있음

여러 개의 사용자 입력 관리하기

여러 개의 사용자 입력을 State로 관리하는 방법
// 이름, 성별, 출생년도, 자기소개를 한 번에 입력하는 예제

import { useState } from "react";

functon Body() {
	const [name, setName] = useState("");
	const [gender, setGender] = useState("");
	const [birth, setBirth] = useState("");
	const [bio, setBio] = useState("");

	const onChangeName = (e) => {
    	setName(e.target.value);
    };
    const cnChangeGender = (e) => {
    	setGender(e.target.value);
    };
    const onChangeBirth = (e) => {
    	setBirth(e.target.value);
    };
    const onChangeBio = (e) => {
    	setBio(e.target.value);
    };
    
    return (
    	<div>
        	<div>
            	<input value={name} onChange={onChangeName} placeholder="이름" />
            	<select value={gender} onChange={cnChangeGender}>
                	<option key={""}></option>
                	<option key={"남성"}>남성</option>
                	<option key={"여성"}>여성</option>
                </select>
            	<input type="date" value={birth} onChange={onChangeBirth} />
            	<textarea value={bio} onChange={onChangeBio} />
            </div>
        </div>
    );
}
export default Body;
사용자로부터 여러 입력 정보를 받아 State로 처리하는 경우, 관리할 State의 개수가 많아지면 코드가 길어지므로, 객체 자료형을 이용해서 간결하게 함

1. 객체 자료형으로 State를 하나 생성하고 초깃값을 설정
2. 모든 입력 폼에서 name 속성을 지정
3. 모든 입력 폼의 value를 객체 state의 프로퍼티 줒ㅇ 하나로 설정
4. 사용자의 입력을 처리할 이벤트 핸들러 handleOnChange를 설정
5. 함수 setState에서는 새로운 객체를 생성해 전달하며, 이때 스프레드 연산자를 이용해 기존 객체 state의 값을 나열하고 객체의 괄호 표기법을 사용하여 입력 폼의 속성과 값을 설정
// 객체 자료형을 이용한 State 관리

import { useState } from "react";

functon Body() {
	const [state, setState] = useState({
    	name: "",
    	gender: "",
    	birth: "",
    	bio: "",
    });

	const handleOnChange = (e) => {
    	setState({
        	...state,
            [e.target.name]: e.target.value,
        });
    };
    
    return (
    	<div>
        	<div>
            	<input name="name" value={state.name} onChange={handleOnChange} placeholder="이름" />
            	<select name="gender" value={state.gender} onChange={handleOnChange}>
                	<option key={""}></option>
                	<option key={"남성"}>남성</option>
                	<option key={"여성"}>여성</option>
                </select>
            	<input name="date" type="date" value={state.birth} onChange={handleOnChange} />
            	<textarea name="bio" value={state.bio} onChange={handleOnChange} />
            </div>
        </div>
    );
}
export default Body;

Props와 State

동적으로 변하는 값인 리액트의 State 역시 일종의 값이므로 Props로 전달 할 수 있으며, 부모 컴포넌트가 State 값이 변해서 리렌더되면 자식도 함께 리렌더 됨
import "./Body.css";
import { useState } from "react";

function Viewer({ number }) {
	return <div>{number % 2 === 0 ? <h3>짝수</h3> : <h3>홀수</h3>}</div>
}

function Body() {
	const [number, setNumber] = setState(0);
    const onIncrease = () => {
    	setNumber(number + 1);
    };
    const onDecrease = () => {
    	setNumber(number - 1);
    };
    return (
    	<div>
        	<h2>{number}</h2>
            <Viewer number={number} />
            
            <div>
            	<button onClick={onDecrease}>-</button>
            	<button onClick={onIncrease}>+</button>
            </div>
        </div>
    );
}
export default Body;

State와 자식 컴포넌트

의미 없는 리렌더가 자주 발생하면 웹 브라우저의 성능은 떨어지며, 이런 성능 낭비를 막는 최적화 기법은 추후에 설명

Ref

리액트의 Ref (Reference) 를 이용하면 돔(DOM) 요소들을 직접 조작할 수 있음

useRef 사용하기

리액트에서는 useRef라는 리액트 함수를 이용해 Ref 객체를 생성

useRef로 입력 폼 초기화하기

대화 상자에서 "확인" 버튼을 클릭하면, textRef.current(textRef가 현재 참조하는 있는 돔 요소)의 value 값을 공백 문자열로 초기화 함

# Ref를 사용하지 않고도 set 함수로 입력 폼을 초기화할 수는 있음
import { useRef, useState } from "react";

function Body() {
	const [text, setText] = useState("");
    const textRef = useRef();
    
    const handleOnChange = (e) => {
    	setText(e.target.value);
    };
    
    const handleOnClick = () => {
    	alert(text);
        textRef.current.value = "";
    };
    
    return (
    	<div>
        	<input ref={textRef} value={text} onChange={handleOnChange} />
            <button onClick={handleOnClick}>작성 완료</button>
        </div>
    );
}
export default Body;

useRef로 포커스하기

폼에 입력한 텍스트가 다섯 글자보다 적다면 textRef.current가 참조하는 입력 폼에 포커스를 실행하는 예제
(...)

const handleOnClick = () => {
	if (text.length < 5) {
    	textRef.current.focus();
    } else {
    	alert(text);
        setText("");
    }
};

(...)
리액트 훅이 발표되기 전까지 함수로 만든 컴포넌트에서는, 클래스로 만든 리액트 컴포넌트인 State나 Ref와 같은 기능을 사용할 수 없었기 때문에, 클래스로 컴포넌트를 작성해야 해서 코드가 너무 많고 문법이 간결하지 못해 불편했음

리액트 훅이란?

함수로 만든 리액트 컴포넌트에서 클래스로 만든 리액트 컴포넌트의 기능을 이용하도록 도와주는 함수로서, 리액트 훅은 이름 앞에 항상 use를 붙임

useState, useRef, useEffect, useContext, useReducer, useCallback, useMemo ...

0개의 댓글