useState
리액트에서 상태 변수를 선언하고 관리하는 데 사용하는 훅입니다.
가장 기본이면서도 가장 많이 사용하는 중요한 훅입니다.
문법
const [state, setState] = useState(initialState);
기본 사용법
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
😵 꼭 count, set*** 형식의 이름이어야 하나요? 아니에요. 배열의 구조 분해 할당을 떠올려보면 이해하기 쉬워요.
배열의 구조 분해를 떠올려 봐요!
const arr = [10, 20, 30];
const [ a, b, c ] = arr; // a: 10, b:20, c:30
const [ x, y, z ] = arr; // x: 10, y:20, z:30
폼 요소
useState를 사용한 상태 관리 변수를 사용해서 폼 입력 요소의 값을 제어할 수 있습니다.
input[type=”text”]
import { useState } from "react";
const App = () => {
const [input, setInput] = useState("");
return (
<div>
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
/>
</div>
);
};
export default App;
input[type=’date’]
import { useState } from "react";
const App = () => {
const [input, setInput] = useState("");
return (
<div>
<input
type="date"
value={input}
onChange={(e) => setInput(e.target.value)}
/>
</div>
);
};
export default App;
textarea
import { useState } from "react";
export const App = () => {
const [textValue, setTextValue] = useState("ab");
return (
<>
<div className="flex flex-col gap-1">
{textValue}
<textarea
className="border border-slate-500"
value={textValue}
onChange={(e) => setTextValue(e.target.value)}
></textarea>
</div>
</>
);
};
select
import { useState } from "react";
const App = () => {
const [input, setInput] = useState("banana");
return (
<div>
<select onChange={(e) => setInput(e.target.value)} value={input}>
<option key={"apple"}>apple</option>
<option key={"banana"}>banana</option>
<option key={"orange"}>orange</option>
</select>
</div>
);
};
export default App;
checkbox
import { useState } from "react";
export const App = () => {
const [checkboxValue, setCheckboxValue] = useState(false);
const [checkboxValue2, setCheckboxValue2] = useState("");
return (
<>
<div className="flex flex-col gap-1">
{checkboxValue ? "Agree" : "!Agree"}
<input
type="checkbox"
className="border border-slate-500"
checked={checkboxValue}
onChange={() => setCheckboxValue(!checkboxValue)}
/>
{checkboxValue2}
<input
type="checkbox"
className="border border-slate-500"
value={checkboxValue2}
onChange={(e) => setCheckboxValue2(e.target.checked ? "checked" : "")}
/>
</div>
</>
);
};
radio
import { useState } from "react";
export const App = () => {
const [radioValue, setRadioValue] = useState("male");
return (
<>
<div>
<input
type="radio"
name="gender"
className="border border-slate-500"
value={"male"}
defaultChecked
onChange={() => setRadioValue("male")}
/>
male
</div>
<div>
<input
type="radio"
name="gender"
className="border border-slate-500"
value={"female"}
onChange={() => setRadioValue("female")}
/>
female
</div>
</>
);
};
종합
import { useState } from "react";
export const App = () => {
const [defaultValue, setDefaultValue] = useState("");
const [textValue, setTextValue] = useState("");
const [dateValue, setDateValue] = useState("");
const [checkboxValue, setCheckboxValue] = useState(false);
const [checkboxValue2, setCheckboxValue2] = useState("");
const [radioValue, setRadioValue] = useState("male");
return (
<>
<div className="item-middle">
<div className="grid gap-3">
<div className="flex flex-col gap-1">
{defaultValue}
<input
type="text"
className="border border-slate-500"
value={defaultValue}
onChange={(e) => setDefaultValue(e.target.value)}
/>
</div>
<div className="flex flex-col gap-1">
{textValue}
<textarea
className="border border-slate-500"
value={textValue}
onChange={(e) => setTextValue(e.target.value)}
></textarea>
</div>
<div className="flex flex-col gap-1">
{dateValue}
<input
type="date"
className="border border-slate-500"
value={dateValue}
onChange={(e) => setDateValue(e.target.value)}
/>
</div>
<div className="flex flex-col gap-1">
{checkboxValue ? "Agree" : "!Agree"}
<input
type="checkbox"
className="border border-slate-500"
checked={checkboxValue}
onChange={() => setCheckboxValue(!checkboxValue)}
/>
{checkboxValue2}
<input
type="checkbox"
className="border border-slate-500"
value={checkboxValue2}
onChange={(e) =>
setCheckboxValue2(e.target.checked ? "checked" : "")
}
/>
</div>
<div className="flex flex-col gap-1">
{radioValue}
<div>
<input
type="radio"
name="gender"
className="border border-slate-500"
value={"male"}
defaultChecked
onChange={() => setRadioValue("male")}
/>
male
</div>
<div>
<input
type="radio"
name="gender"
className="border border-slate-500"
value={"female"}
onChange={() => setRadioValue("female")}
/>
female
</div>
</div>
</div>
</div>
</>
);
};
useRef
useRef는 리액트에서 HTML 요소에 접근하거나 컴포넌트의 렌더링에 영향없이 값을 유지하고 싶을 때 사용합니다.
문법
const ref = useRef(initialValue);
사용 예시
ex1)
import { useState } from "react";
interface Todo {
id: number;
text: string;
}
const App = () => {
let uid = 1;
const [todos, setTodos] = useState<Todo[]>([]);
const addTodo = () => {
const todo = {
id: uid++,
text: "아침먹기",
};
setTodos((prev) => [...prev, todo]);
};
return (
<div>
<h1>할일 관리하기</h1>
<pre>{JSON.stringify(todos)}</pre>
<button onClick={addTodo}>할일추가</button>
</div>
);
};
export default App;
ex2)
import { useRef, useState } from "react";
interface Todo {
id: number;
text: string;
}
const App = () => {
let uid = useRef(1);
const [todos, setTodos] = useState<Todo[]>([]);
const addTodo = () => {
const todo = {
id: uid.current++,
text: "아침먹기",
};
setTodos((prev) => [...prev, todo]);
};
return (
<div>
<h1>할일 관리하기</h1>
<pre>{JSON.stringify(todos)}</pre>
<button onClick={addTodo}>할일추가</button>
</div>
);
};
export default App;
ex3)
import { useRef } from "react";
const App = () => {
const inputEl = useRef<HTMLInputElement>(null);
const onButtonClick = () => {
inputEl.current?.focus();
};
return (
<div>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</div>
);
};
export default App;
useEffect
useEffect 훅은 컴포넌트 생명 주기에 따른 코드를 작성하고 싶을 때 사용할 수 있는 훅입니다. 아래와 같은 기본 문법 형식을 가집니다.
useEffect(콜백, 의존성배열); // dependencies array
useEffect(() => {}, []);
컴포넌트 생명주기
컴포넌트 생명주기란, 컴포넌트가 생성되고 삭제가 되는 순간까지 거쳐가는 일련의 주기를 말합니다. 리액트에서는 컴포넌트 생명주기를 ‘생성’, ‘수정(업데이트)’, ‘삭제’의 세 가지로 구분하고 있습니다.
컴포넌트 생성
컴포넌트가 생성되는 시점은 특정 컴포넌트가 웹 브라우저에 렌더링 되는 순간입니다.
컴포넌트 삭제
컴포넌트가 삭제되는 시점은 특정 컴포넌트가 웹 브라우저에서 사라지는 순간입니다.
컴포넌트 수정
컴포넌트가 수정되는 시점은 컴포넌트에서 관리하고 있는 상태 관리 변수의 값이 변경되었을 때입니다.
useEffect() 훅 사용하기
컴포넌트 생명주기의 각 시점은 useEffect() 훅으로 체크할 수 있습니다.
컴포넌트 생성 시점
import { useEffect } from "react";
export default function App() {
useEffect(() => {
console.log("Component Created");
}, []);
return <h1 className="text-3xl font-bold underline">Hello world!</h1>;
}
컴포넌트 수정 시점
import { useEffect, useState } from "react";
export default function App() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log("Component Count Updated!" + count);
}, [count]);
return (
<>
<h1>{count}</h1>
<button onClick={() => setCount((count) => count + 1)}>클릭</button>
</>
);
}
컴포넌트 삭제 시점
App.tsx
import { useState } from "react";
import Interval from "./components/Interval";
export default function App() {
const [display, setDisplay] = useState(false);
return (
<>
{display && <Interval />}
<button onClick={() => setDisplay((display) => !display)}>클릭</button>
</>
);
}
Interval.tsx
import { useEffect } from "react";
const Interval = () => {
useEffect(() => {
const interval = setInterval(() => {
console.log("Interval Component Updated!");
}, 1000);
return () => {
clearInterval(interval);
};
}, []);
return (
<>
<h1>Interval Component</h1>
</>
);
};
export default Interval;
useLayoutEffect
useEffect() 훅과 똑같은 개념이지만, 실행되는 방식에서 차이가 발생합니다.
useEffect() 훅은 화면에 컴포넌트가 렌더링 된 후 비동기적으로 실행됩니다. 그래서 DOM을 조작하는 경우 ‘깜빡임’을 볼 수 있을 확률이 높습니다.
useLayoutEffect()는 화면에 컴포넌트를 그리기 바로 직전에 동기적으로 실행됩니다. 그래서 DOM을 조작하는 경우 ‘깜빡임’을 볼 수 없습니다.
예제 1
import { useEffect, useLayoutEffect, useState } from "react";
const UseLayoutEffect = () => {
const [value, setValue] = useState(0);
const [value2, setValue2] = useState(0);
useEffect(() => {
if (value === 0) {
setValue(10 + Math.random() * 200);
}
}, [value]);
useLayoutEffect(() => {
if (value2 === 0) {
setValue2(10 + Math.random() * 200);
}
}, [value2]);
console.log("render", value);
return (
<>
<button onClick={() => setValue(0)}>useEffect value: {value}</button>
<br />
<button onClick={() => setValue2(0)}>
useLayoutEffect value2: {value2}
</button>
</>
);
};
export default UseLayoutEffect;
예제 2
import { useEffect, useLayoutEffect, useState } from "react";
const UseLayoutEffect = () => {
const [count, setCount] = useState(0);
const now = performance.now();
while (performance.now() - now < 200) {
// Artificial delay -- do nothing
}
useLayoutEffect(() => {
if (count === 10) setCount(0);
console.log("useLayoutEffect");
}, [count]);
return (
<>
<h1>Count: {count} </h1>
<button onClick={() => setCount(10)}>클릭</button>
</>
);
};
export default UseLayoutEffect;
[스나이퍼 팩토리 리액트 2기 과정]
본 학습 자료 및 코드는 수코딩님의 자료를 이용하였습니다. [수코딩(https://www.sucoding.kr)] 출처
'프론트엔드(Web) > React' 카테고리의 다른 글
리액트 메모이제이션- useCallback,useMemo,React.memo,useReducer (4) | 2024.08.27 |
---|---|
리액트 훅 리액트 18 + - useId,동시성 모드 훅(useTransition,useDefferedValue,useTransition vs useDeferredValue) (0) | 2024.08.27 |
리액트 - 컴포넌트 기본문법(컴포넌트 생성, props, children, 조건부 및 반복 , 이미지 렌더링) (0) | 2024.08.25 |
리액트 - 폰트 지정하는 방법 (0) | 2024.08.21 |
리액트 - 컴포넌트 및 컴포넌트 css 스타일링 (0) | 2024.08.20 |