
저번 시간 내용 복습✨
함수형 컴포넌트를 사용하는 데 집중해보자!
hook을 사용해서 사이드 이펙트 처리
props: 컴포넌트 자체에서 변화시킬 수 없다
state: 컴포넌트 내에서 저장되고 변화시킬 수 있는 값
react hook: 모든 컴포넌트를 독립적으로 재사용 가능
component 가 변경되면 해당 컴포넌트 함수를 다시 실행 = 다시 그린다
useEffect(effectCallback:Fn, deps:Array): state 가 변경되면 전체 컴포넌트가 다시 실행된다 - 인자가 변경되면 첫 번째 인자의 함수를 다시 실행하는 것
실습을 위한 예제 문제)
아래와 같이 작성하면, 1초에 한 번씩 깜빡이는 텍스트를 만들 수 있다.


연습문제4)
버튼을 클릭할 때마다 "ON"과 "OFF"로 상태가 바뀌는 토글 버튼을 만드세요. 상태가 변경될 때마다 useEffect를 사용해 콘솔에 메시지를 출력하세요.
(설명)
버튼의 텍스트는 상태에 따라 "ON" 또는 "OFF"로 변경됩니다.
상태가 변경될 때마다 useEffect를 사용해 콘솔에 "Toggle is ON" 또는 "Toggle is OFF" 메시지를 출력합니다.
import { useState, useEffect } from "react";
export const ToggleButton = () => {
const [isOn, setIsOn] = useState(false);
const handleToggle = () => {
setIsOn((prev) => !prev);
};
useEffect(() => {
console.log(`Toggle is ${isOn ? "ON" : "OFF"}`);
}, [isOn]);
return (
<button onClick={handleToggle}>
{isOn ? "ON" : "OFF"}
</button>
);
};
연습문제5) 금지어 사전 및 필터링
금지어 사전 만들기 (컴포넌트 이름 자유) : 사용자로부터 input에 입력을 받아, Add 버튼을 클릭하면 금지어가 추가되도록 작성하시오. 금지어는 실시간으로 사용자 화면에 렌더링 되어야 합니다. (입력: onChange 이벤트 활용)
사용자로부터 입력받아 금지어 필터링 하기 : input태그를 하나 만들고 사용자로부터 입력을 받아, 화면 아래에 렌더링 하시오.

import { useState } from "react";
export default function SlangFiltering() {
const [input, setInput] = useState(""); // 금지어 입력
const [slangs, setSlangs] = useState([]); // 금지어 리스트
const [sentence, setSentence] = useState(""); // 사용자가 지금 입력 중인 문장
const [userInputs, setUserInputs] = useState([]); // 누적된 사용자 입력 리스트
const handleSlangAdd = () => {
const trimmed = input.trim();
if (trimmed && !slangs.includes(trimmed)) {
setSlangs((prev) => [...prev, trimmed]);
setInput("");
}
};
const handleSentenceAdd = () => {
if (sentence.trim()) {
setUserInputs((prev) => [...prev, sentence]);
setSentence("");
}
};
const getFilteredText = (text) => {
let filtered = text;
slangs.forEach((slang) => {
const regex = new RegExp(slang, "gi");
filtered = filtered.replace(regex, "**");
});
return filtered;
};
return (
<div style={{ display: "flex", justifyContent: "space-between", padding: " 50px 100px" }}>
<div style={{ flex: 1 }}>
<label>
사용자 입력{" "}
<input
value={sentence}
onChange={(e) => setSentence(e.target.value)}
/>
</label>
<button onClick={handleSentenceAdd}>Add</button>
<ul>
{userInputs.map((text, index) => (
<li key={index}>{getFilteredText(text)}</li>
))}
</ul>
</div>
<div style={{ flex: 1, textAlign: "right" }}>
<label>
금지어 입력{" "}
<input
value={input}
onChange={(e) => setInput(e.target.value)}
/>
</label>
<button onClick={handleSlangAdd}>Add</button>
<ul>
{slangs.map((word, index) => (
<li key={index}>{word}</li>
))}
</ul>
</div>
</div>
);
}

연습문제6) - 데이터 통신하여 렌더링하기
컴포넌트가 처음 렌더링될 때 https://jsonplaceholder.typicode.com/users 에서 데이터를 가져와 화면에 표시하세요. useEffect를 사용해 데이터 fetch가 한 번만 실행되도록 하세요. → (username과 email만 렌더링 되도록)
설명:
공개 API를 사용합니다.
컴포넌트가 처음 마운트될 때만 한 번 데이터를 가져오도록 useEffect를 설정합니다.
username과 email이 보이도록 ul 과 li 태그를 이용하여 렌더링하세요.
import { useState, useEffect } from "react";
export default function Rendering() {
const [users, setUsers] = useState([]);
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/users")
.then((res) => res.json())
.then((data) => setUsers(data))
.catch((error) => console.error("실패:", error));
}, []);
return (
<div style={{ padding: "20px 30px" }}>
<h2>UserName & E-mail</h2>
<ul>
{users.map((user) => (
<li key={user.id}>
{user.username} - {user.email}
</li>
))}
</ul>
</div>
);
}

연습문제7) - 스탑워치 만들기
문제: "Start" 버튼을 누르면 스탑워치가 시작되고, "Stop" 버튼을 누르면 스탑워치가 멈추며, "Reset" 버튼을 누르면 스탑워치의 값이 0으로 초기화되는 스탑워치를 만드세요. 타이머 기능은 useEffect를 사용해 구현하세요.
설명:
현재 스탑워치 값을 0부터 시작해 표시합니다.
"Start" 버튼을 누르면 스탑워치가 1초마다 증가하고, "Stop" 버튼을 누르면 스탑워치가 멈춥니다.
"Reset" 버튼을 누르면 스탑워치가 0으로 초기화됩니다.
스탑워치가 실행될 때마다 useEffect를 사용해 매초 스탑워치 값을 업데이트합니다.
import { useState, useEffect } from "react";
export default function Stopwatch() {
const [seconds, setSeconds] = useState(0);
const [isRunning, setIsRunning] = useState(false);
useEffect(() => {
let timer;
if (isRunning) {
timer = setInterval(() => {
setSeconds((prev) => prev + 1);
}, 1000);
}
return () => clearInterval(timer);
}, [isRunning]);
const handleStart = () => setIsRunning(true);
const handleStop = () => setIsRunning(false);
const handleReset = () => {
setIsRunning(false);
setSeconds(0);
};
return (
<div>
<h2>스탑워치: {seconds}초</h2>
<button onClick={handleStart} disabled={isRunning}>Start</button>
<button onClick={handleStop} disabled={!isRunning}>Stop</button>
<button onClick={handleReset}>Reset</button>
</div>
);
}

연습문제8) - 타이머 만들기
문제: 사용자의 입력된 시간에 따라 타이머가 실행되도록 하세요.
→ 타이머가 종료되면, 타이머가 끝났다는 메시지를 alert로 화면에 띄우는 기능을 구현하세요.
→ useEffect를 사용해 타이머가 설정된 시간이 끝났을 때 메시지를 표시합니다.
설명:
1. 타이머가 시작되면 10초 후 자동으로 종료되도록 설정합니다.
2. 타이머가 끝나면"타이머 종료" 메시지를 화면에 표시합니다.
3. useEffect를 사용해 타이머가 종료되었는지 체크합니다.
심화:
1. 사용자로부터 시간을 입력받아서 타이머가 실행되도록 하자.
import { useState, useEffect } from "react";
export default function CountdownTimer() {
const [inputTime, setInputTime] = useState(""); // 사용자가 입력한 시간
const [timeLeft, setTimeLeft] = useState(0); // 실제 줄어드는 시간
const [isRunning, setIsRunning] = useState(false);
useEffect(() => {
let timer;
if (isRunning && timeLeft > 0) {
timer = setInterval(() => {
setTimeLeft((prev) => prev - 1);
}, 1000);
}
if (isRunning && timeLeft === 0) {
alert("타이머 종료");
setIsRunning(false);
}
return () => clearInterval(timer);
}, [isRunning, timeLeft]);
const handleStart = () => {
const parsed = parseInt(inputTime);
if (isNaN(parsed) || parsed <= 0) {
alert("양의 정수를 입력하세요.");
return;
}
setTimeLeft(parsed);
setIsRunning(true);
};
const handleReset = () => {
setInputTime("");
setTimeLeft(0);
setIsRunning(false);
};
return (
<div>
<h2>남은 시간: {timeLeft}초</h2>
<input
type="number"
placeholder="초 입력"
value={inputTime}
onChange={(e) => setInputTime(e.target.value)}
disabled={isRunning}
/>
<button onClick={handleStart} disabled={isRunning}>Start</button>
<button onClick={handleReset}>Reset</button>
</div>
);
}

오늘의 중요한 내용✨
useState 왜 사용할까?
state 란 컴포넌트 내부에서 변경될 수 있는 데이터, 이 데이터(변수)가 바뀔 때마다 ui 를 랜더링함
ui를 다시 랜더링한다 = 컴포넌트 함수를 다시 실행시킨다
- 그러면 언제 실행시켜야 하지??? 이걸 알기 위해 useState 사용! useState가 값이 변경되는지 감시하고 있다가 자동으로 랜더링해줌
- 만약 사용하지 않으면? React는 데이터가 바뀌었는지 몰라서 UI를 다시 그리지 않음 = 즉, 화면에는 변화가 반영되지 않음, 그래서 useState 사용해야 한다!
useEffect 왜 사용할까?
useEffect 는 화면 그리는 것과 별개로 필요한 동작을 실행할 때 사용하는 것임, 예를 들어 버튼 클릭시 콘솔에 로그 출력, 이벤트 리스너 등의 동작은 render 와는 별개의 동작(side effect) 이고, 이 때 useEffect 가 필요한 것임
useEffect(effectCallback:Fn, deps:Array)
- dependency array에 있는 값이 변경될 때마다 첫 번째 인자인 함수가 실행, 만약 여기에 포함되지 않은 인자가 변경된다면 그냥 continue
불필요한 fetch 요청을 보낼 필요가 없고, 데이터가 변경될 때만 함수가 호출됨 = 낭비가 없다!
'Education > 신한투자증권 프로 디지털 아카데미' 카테고리의 다른 글
| Express, MongoDB 로 Postman 에서 통신하기 (3) | 2025.06.14 |
|---|---|
| React hook 알아보기 (3) | 2025.06.10 |
| TypeScript 기초 & React 기초 (2) | 2025.06.08 |
| JavaScript 크롤링 딥 다이브💦 (7) | 2025.06.06 |
| JavaScript cheerio 사용해서 크롤링 해보기 (2) | 2025.06.06 |