JavaScript

웹 개발의 필수 언어

동적인 웹 페이지 구현을 위한 핵심 프로그래밍 언어.

Java

객체지향 프로그래밍

안정적이고 확장성 있는 백엔드 개발의 대표 언어.

HTML

웹의 기초

웹 페이지의 구조를 정의하는 마크업 언어.

React

현대적 UI 라이브러리

효율적인 사용자 인터페이스 구축을 위한 JavaScript 라이브러리.

CSS

웹 디자인의 핵심

웹 페이지의 시각적 표현을 담당하는 스타일 언어.

Spring

자바 웹 프레임워크

기업급 애플리케이션 개발을 위한 강력한 프레임워크.

React/예제

useEffect 예제 - 랜덤 강아지 이미지(무한 새로고침)

lamarcK 2025. 4. 9. 00:58

useEffect를 활용하여 컴포넌트가 마운트되었을 때와 언마운트될 때의 동작을 구현합니다.

예를 들어, API 데이터를 불러와서 컴포넌트에 표시하는 작업을 수행합니다.

이 경우엔 자동 새로고침으로 특정 시간마다 계속해서 강아지의 이미지를  새로고침하는 방식으로 구현됐습니다.

 

useEffect를 통해서 토글 버튼의 동작(isLoading) 감지 후 딜레이를 확인하고 무한 새로고침을 실시하며

토글 버튼을 다시 누를 경우 false를 반영해서 클린업으로 setinterval을 삭제합니다.

useEffect(() => {
  
    const value = Math.min(10, Math.max(1, parseInt(delay) || 1))
    let inter;
    if(isLoading){
      fetchDog()

      inter = setInterval(()=>{
        fetchDog()
      },value*1000)
    }
    return () => {
      if (inter) clearInterval(inter); // intervalId가 존재하면 타이머 중지
    };
  }, [isLoading])

 

js 코드

더보기
import { useState, useEffect } from 'react'
import './App.css'

// App.jsx

function App() {
  const [dogImage, setDogImage] = useState('')
  const [isLoading, setIsLoading] = useState(false)
  const [delay, setdelay] = useState('5')
  const [error, setError] = useState(null)
  

    // async로 dog 이미지 로딩 기다림
      const fetchDog = async () => {
        console.log("불러옴")
        //새로고침 중임을 확인 true
        try {
          const response = await fetch('https://dog.ceo/api/breeds/image/random')
          const data = await response.json()
          setDogImage(data.message)
          setError(null)
        } catch (err) {
          setError('강아지 이미지를 가져오는데 실패했습니다.')
        } finally {
        }
      }
  //isrefresh 변경 시 딜레이 세팅하도록 수정정
  useEffect(() => {
  
    const value = Math.min(10, Math.max(1, parseInt(delay) || 1))
    let inter;
    if(isLoading){
      fetchDog()

      inter = setInterval(()=>{
        fetchDog()
      },value*1000)
    }
    return () => {
      if (inter) clearInterval(inter); // intervalId가 존재하면 타이머 중지
    };
  }, [isLoading])

//토글 방식
const toggle =()=>{
//껐다 키기
if (isNaN(delay)){
  alert("숫자만 입력해주세요");
}
else setIsLoading(!isLoading)
}

  return (
    <div className="container">
      <h1>🐕 랜덤 강아지 이미지 🐕</h1>
      {error && <p className="error">{error}</p>}
      {dogImage && (
        <div className="dog-img">
          <img 
            src={dogImage} 
            alt="Random Dog" 
            className="dog-box"
          />
        </div>
      )}
      <div>
      <input type='textbox' className='inputdelay'
      value={delay}
      onChange={(e) => setdelay(e.target.value)}
      placeholder="새로고침 간격" 
      ></input>
      <span>초</span>
      <div>(최소 : 1, 최대 : 10초)</div>
      </div>
      <button 
        onClick={toggle} 
        className={isLoading?"load":""}
              >
        {isLoading ? '새로고침\n멈추기' : '새로운\n강아지 보기'}
      </button>
    </div>
  )
}

export default App

css 코드

더보기
#root {
  max-width: 1280px;
  margin: 0 auto;
  padding: 2rem;
  text-align: center;
}

.container{
  width: fit-content;
  height: fit-content;
  display: flex;
  flex-direction: column;

  align-items: center;
}

.dog-box{
  border-radius: 25px;
  max-height: 300px;
  height: 300px;
  object-fit: cover;
}

button.load{
  background-color: #888;
}

button {
  margin: 20px;
  border-radius: 8px;
  height: 100px;
  width: 200px;
  max-height: 100px;
  max-width: 200px;
  border: 1px solid transparent;
  padding: 0.6em 1.2em;
  font-size: 1.5em;
  font-weight: 800;
  background-color: azure;
  border-radius: 25px;
  font-family: inherit;
  cursor: pointer;
  transition: border-color 0.25s;
  white-space: pre-line;
}

button:disabled {
  background: linear-gradient(to bottom, #ffffff, #cccccc);
  color: #888;
  cursor: not-allowed;
  border: 1px solid #ccc;
}

.inputdelay{
  width: 100px;
}

:root {
  font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
  line-height: 1.5;
  font-weight: 400;

  color-scheme: light dark;
  color: rgba(255, 255, 255, 0.87);
  background-color: #242424;

  font-synthesis: none;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

a {
  font-weight: 500;
  color: #646cff;
  text-decoration: inherit;
}
a:hover {
  color: #535bf2;
}

body {
  margin: 0;
  display: flex;
  place-items: center;
  min-width: 320px;
  min-height: 100vh;
}

h1 {
  font-size: 3.2em;
  line-height: 1.1;
}


button:hover {
  border-color: #646cff;
}
button:focus,
button:focus-visible {
  outline: 4px auto -webkit-focus-ring-color;
}

@media (prefers-color-scheme: light) {
  :root {
    color: #213547;
    background-color: #ffffff;
  }
  a:hover {
    color: #747bff;
  }
  button {
    background-color: #f9f9f9;
  }
}