1. useState
정의
useState는 리액트의 기본 훅 중 하나로, 함수 컴포넌트에서 가변적인 상태를 관리할 수 있게 해줌
useState를 사용하면 컴포넌트 내에서 상태를 정의하고, 그 상태를 업데이트할 수 있음
setState를 사용하는 두 가지 방법: 일반적인 값 업데이트와 함수형 업데이트 방식
일반 업데이트
- 여러 번 호출해도 마지막 호출만 적용 (각각 실행되는 것이 아니라 배치 업데이트로 처리함) => set을 동일요청으로 판단하여 한 번만 업데이트 함
- Why? 불필요한 렌더링을 방지하기 위해서 (=렌더링 최적화를 위해)
import React from "react";
import { useState } from "react";
const App = () => {
const [count, setCount] = useState(0);
return (
<div>
{count}
<button
onClick={() => {
// 1. useState 일반 사용법
// 아래 setCount는 3이 증가하는 것이 아니라 1 증가
setCount(count + 1);
setCount(count + 1);
setCount(count + 1);
}}
>
Plus
</button>
);
};
export default App;
함수형 업데이트
- 모든 호출이 순차적으로 적용
- 장점: prop drilling을 예방할 수 있음
- 언제 사용?
- 현재 상태를 기반으로 새로운 상태를 계산하는 데 유용
- 연속적인 상태 변경이 발생하는 경우 유용
const filterByAge = (minAge) => {
setFilteredStudents(students); // 초기화 후 필터
setFilteredStudents(prev => prev.filter(student => student.age >= minAge)); // prev에는 students가 들어옴
};
import React from "react";
import { useState } from "react";
const App = () => {
const [count, setCount] = useState(0);
return (
<div>
{count}
<button
onClick={() => {
// 2. 함수형 업데이트
// 아래 setCount는 + 3이 증가: 세 번을 동시에 명령을 내리게 되면, 이 명령을 모아 순차적으로 한 번씩 실행시킴
setCount((prev) => prev + 1); // 최초 값 0 이 들어와 prev이 1이 됨
setCount((prev) => prev + 1); // 다음 setCount에서 이전 prev값 1을 인자로 가져와 1+1 =2가됨
setCount((prev) => prev + 1); // 2가 인자로 들어와 2+1 = 3이 리턴이 됨
}}
>
Plus
</button>
);
};
export default App;
부모-자식 컴포넌트에서 state 변경
- 부모 컴포넌트의 상태를 자식 컴포넌트에서 변경하려면, setState 함수를 props로 전달하는 것이 효율적
- 함수형 업데이트 방식을 사용하면 불필요한 상태 전달을 줄일 수 있음
import React from "react";
import { useState } from "react";
import Child from "./components/Child";
const App = () => {
const [count, setCount] = useState(0);
return (
<div>
<h1>여기는 부모 컴포넌트입니다.</h1>
<span>현재 카운트: {count}</span>
<Child setCount={setCount} />
</div>
);
};
export default App;
// src > components > Child.jsx
const Child = ({ count, setCount }) => {
return (
<div>
<h3>여기는 자식 컴포넌트 입니다.</h3>
<button
onClick={() => {
// 1. 일반 업데이트 방식
setCount(count + 1);
}}
>
Count 1 증가
</button>
</div>
);
};
export default Child;
// src > components > Child.jsx
const Child = ({ setCount }) => {
return (
<div>
<h3>여기는 자식 컴포넌트 입니다.</h3>
<button
onClick={() => {
// 함수형 컴포넌트 사용 예, 함수형 컴포넌트를 사용하면 count까지 내려받을 필요가 없음
setCount((prev) => prev + 1);
}}
>
Count 1 증가
</button>
</div>
);
};
export default Child;
리액트의 설계 이유
리액트는 성능 최적화를 위해 상태 업데이트를 단일 업데이트로 처리합니다. 이는 불필요한 리렌더링을 방지하고, 리소스 효율성을 높이기 위함입니다.
2. useEffect
정의
- useEffect는 리액트 컴포넌트가 렌더링된 후 특정 작업을 수행할 수 있도록 하는 훅
- 컴포넌트가 마운트되거나 업데이트될 때 실행
의존성 배열
- useEffect는 의존성 배열을 통해 실행 시점을 제어할 수 있음
- 빈 배열을 전달하면 처음 렌더링 시에만 실행되고, 특정 값을 배열에 넣으면 그 값이 변경될 때만 실행
- 값이 입력됨에 따라 컴포넌트가 리렌더링되며 useEffect가 다시 호출되기 때문에, useEffect의 두 번째 인자인 의존성 배열로 이 문제를 해결할 수 있음 (의존성 배열: setEffect가 의존하고 있는 값의 배열 => 이 배열에 값을 넣으면 그 값이 바뀔 때만 useEffect를 실행 => 두 번째 인자에 배열을 넣고 어떤 값이 바뀔 때만 useEffect를 실행할 지 명시)
import React, { useEffect, useState } from "react";
const App = () => {
const [value, setValue] = useState("");
const [count, setCount] = useState(0);
// 값을 입력함에 따라 useEffect가 호출: 컴포넌트가 리렌더링되며 useEffect가 다시 호출되기 때문에
// useEffect(() => {
// // 최초에 한 번만 찍히길 원했지만 input을 입력할 때마다 찍히고 있음
// // => useEffect의 두 번째 인자인 의존성 배열로 해결 가능
// // 의존성 배열: useEffect가 의존하고 있는 값의 배열 => 이 배열에 값을 넣으면 그 값이 바뀔 때만 useEffect를 실행할게!
// console.log("Hello, useEffect.");
// });
// 두 번째 인자에 배열을 넣어줌: 그리고 어떤 값이 바뀔 때만 useEffect를 실행할지 명시
// 현재 의존성 배열이 빈 배열 => trigger가 없음, 이런 경우 컴포넌트가 최초 렌더링이 됬을 때에만 이 로직이 수행이 됨,
// 만약 배열에 어떤 값을 넣으면, 그 값을 참조하여 계속해서 수행됨
useEffect(() => {
console.log("Hello, useEffect.");
}, []);
return (
<div>
<h1>useEffect</h1>
{/* 값이 입력됨에 따라 value에 해당되는 state가 변경되면서 리렌더링이 됨*/}
{/* input에 값 입력 -> value의 state가 변경 -> App 컴포넌트가 리렌더링 됨 -> useEffect() 다시 실행*/}
<input
type='text'
value={value} //
onChange={(e) => {
setValue(e.target.value); //
}}
/>
{count}
<button
onClick={() => {
setCount(count + 1);
}}
>증가</button>
</div>
);
};
export default App;
클린업 함수
- useEffect는 컴포넌트가 언마운트될 때 클린업 함수를 실행할 수 있음
- 이 클린업 함수는 컴포넌트가 사라질 때 실행되며, 주로 리소스 해제나 정리 작업에 사용
3. useRef
정의
- useRef는 리액트에서 DOM 요소에 접근하거나, 상태 변화에 영향을 받지 않는 변수를 관리하는 데 사용
- useRef로 생성된 객체는 컴포넌트가 리렌더링되더라도 값이 변하지 않음
- useState처럼 저장공간의 역할을 하지만, useState는 렌더링을 일으키고, useRef로 선언한 값은 값을 바꾸어도 렌더링이 일어나지 않음
DOM 접근 및 유지
- useRef를 사용하면 직접 DOM 요소에 접근할 수 있으며, 이 접근은 컴포넌트가 리렌더링되더라도 변하지 않음
- 따라서 포커스 제어, 서드파티 라이브러리와의 통합 등에 주로 사용됨
저장 공간으로 사용
- 상태 업데이트 없이 값을 유지해야 할 때도 useRef를 사용할 수 있음
- 예를 들어, 이전 상태를 저장하거나 특정 값의 변화를 추적하는 데 유용
import React from "react";
import { useRef, useState, useEffect } from "react";
const App = () => {
// ---------- (1) useRef vs useState ----------
const [count, setCount] = useState(0);
const countRef = useRef(0);
// setCount를 이용해 count를 갱신
const plusStateCountButtonHandler = () => {
setCount(count + 1);
};
// countRef에 있는 current에 접근을 해서 ++
const plusRefCountButtonHandler = () => {
countRef.current++;
};
return (
<>
{/* ---------- (1) useRef vs useState ---------- */}
<div>
<h1>useRef vs useState</h1>
<div>
state영역입니다. {count}
<br />
<button onClick={plusStateCountButtonHandler}>state 증가</button>
</div>
<div>
ref영역입니다. {countRef.current}
<br />
<button onClick={plusRefCountButtonHandler}>ref 증가</button>
</div>
</div>
</>
);
};
export default App;
import React from "react";
import { useRef, useState, useEffect } from "react";
const App = () => {
// ---------- (2) 아이디 / 비밀번호 ----------
const idRef = useRef("");
// 최초 렌더링 시에만 아이디 포커싱
useEffect(() => {
idRef.current.focus();
}, []);
return (
<>
{/* ---------- (2) 아이디 / 비밀번호 ---------- */}
<div>
<div>
아이디: <input type='text' ref={idRef} />
</div>
<div>
비밀번호: <input type='password' />
</div>
</div>
</>
);
};
export default App;
4. useContext
정의
useContext는 리액트에서 컴포넌트 트리 전체에 걸쳐 전역적인 데이터를 공유할 수 있는 방법을 제공합니다. useContext를 사용하면 props를 통해 데이터를 전달할 필요 없이, 전역 상태에 직접 접근할 수 있습니다.
컨텍스트 생성 및 사용
컨텍스트는 React.createContext로 생성하며, 이를 Provider로 감싸서 하위 컴포넌트들이 접근할 수 있게 합니다. useContext를 사용하면 해당 컨텍스트의 값을 읽어올 수 있습니다.
컨텍스트와 상태 관리
상태 관리 라이브러리 없이도 useContext와 useReducer를 결합하여 복잡한 전역 상태 관리를 수행할 수 있습니다. 이는 작은 규모의 애플리케이션에서 유용합니다.
'⚛️ React 공부 > 기초 문법' 카테고리의 다른 글
| ReactJS 숙련: Redux 리덕스, counter 기능 구현하기 (0) | 2024.08.21 |
|---|---|
| ReactJS 숙련: Hooks (Memorization, CustomHook) (0) | 2024.08.20 |
| ReactJS 숙련: CSS-in-JS와 Styled-Components (0) | 2024.08.16 |
| ReactJS 입문: React 소개와 프로젝트 생성 (0) | 2024.08.13 |
| ReactJS 기초 (0) | 2024.08.09 |