생활코딩! React 리액트 프로그래밍

egoing - useReducer - stackblitz ver

lshjju 2025. 9. 6. 14:57

useReducer


https://lshjju.tistory.com/148

 

React.js - useReducer - 리액트 유즈리듀서

React useReducer 란 무엇인가요? 이번에는 React의 또 다른 중요한 Hook인 **useReducer**에 대해 알기 쉽게 설명해 드릴게요.useState가 간단한 상태 관리에 유용하다면, useReducer는 조금 더 복잡하고 체계적

lshjju.tistory.com



Final build


https://stackblitz.com/edit/vitejs-vite-oxor1rrt?file=src%2FApp.jsx

 

egoing - useReducer - StackBlitz

Next generation frontend tooling. It's fast!

stackblitz.com



New project building


https://lshjju.tistory.com/104

 

StackBlitz web editor - 스택블리츠 웹 에디터

스택블리츠로 새 프로젝트 생성하기 https://stackblitz.com/ 로그인 방법 선택 대쉬보드에서 new project + 버튼 - 탭 모달 - frontend 탭 - 탭react javascript - 탭 바이트 리액트가 생성됩니다.프로젝트 생성 완

lshjju.tistory.com



스테이트 카운트앱 유아이 만듭니다.


스테이트 카운트앱 빌딩 스텝

 

버튼유아이 

카운트 초기화

카운트 데이터 바인딩

연산 펑션

버튼유아이에 펑션콜 추가

테스트


export default function App() {
  return (
    <div>
      <input type="button" value="-" />
      <input type="button" value="0" />
      <input type="button" value="+" />
    </div>
  );
}

 

카운터 유아이를 만듭니다.


import { useState } from "react";

 

유즈스테이트를 임포트 합니다.

스택블리츠는 디폴트로 임포트 되어 있으니 안해도 됩니다.


  const [count, setCount] = useState(0);

 

리턴 위에 카운트를 유즈스테이트로 초기화 합니다.


      <span>{count}</span>

 

버튼 아래에 카운트를 데이터바인딩 합니다.


test

 

데이터 바인딩을 체크 합니다.


Completion

import { useState } from 'react'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'

export default function App() {
  const [count, setCount] = useState(0);
  return (
    <div>
      <input type="button" value="-" />
      <input type="button" value="0" />
      <input type="button" value="+" />
      <span>{count}</span>
    </div>
  );
}


카운트앱 기능을 구현 합니다.


  function down() {
    setCount(count - 1);
  }
  function reset() {
    setCount(0);
  }
  function up() {
    setCount(count + 1);
  }

 

카운트 변수 아래에 연산 펑션을 추가합니다.

  // 'count' 값을 1 감소시키는 함수입니다.
  // 이 함수는 '하향(-)' 버튼이 클릭될 때 호출됩니다.
  function down() {
    setCount(count - 1);
  }
  
  // 'count' 값을 초기값인 0으로 재설정하는 함수입니다.
  // 이 함수는 '재설정(0)' 버튼이 클릭될 때 호출됩니다.
  function reset() {
    setCount(0);
  }
  
  // 'count' 값을 1 증가시키는 함수입니다.
  // 이 함수는 '상향(+)' 버튼이 클릭될 때 호출됩니다.
  function up() {
    setCount(count + 1);
  }

      <input type="button" value="-" onClick={down} />
      <input type="button" value="0" onClick={reset} />
      <input type="button" value="+" onClick={up} />

 

버튼유아이에 펑션콜 추가합니다.

      {/* '하향(-)' 기능을 수행하는 버튼입니다. 클릭 시 down 함수가 호출됩니다. */}
      <input type="button" value="-" onClick={down} />
      {/* '초기화(0)' 기능을 수행하는 버튼입니다. 클릭 시 reset 함수가 호출됩니다. */}
      <input type="button" value="0" onClick={reset} />
      {/* '상향(+)' 기능을 수행하는 버튼입니다. 클릭 시 up 함수가 호출됩니다. */}
      <input type="button" value="+" onClick={up} />

test

 

카운트 앱이 잘 작동하는지 체크 합니다.


Completion

import { useState } from 'react';
import reactLogo from './assets/react.svg';
import viteLogo from '/vite.svg';
import './App.css';

export default function App() {
  const [count, setCount] = useState(0);

  function down() {
    setCount(count - 1);
  }
  function reset() {
    setCount(0);
  }
  function up() {
    setCount(count + 1);
  }

  return (
    <div>
      <input type="button" value="-" onClick={down} />
      <input type="button" value="0" onClick={reset} />
      <input type="button" value="+" onClick={up} />
      <span>{count}</span>
    </div>
  );
}


카운트 기능을 유즈리듀서로 업그레이드 합니다.


import { useReducer } from "react";

 

유즈스테이트를 유즈리듀서로 업그레이드 하기 위해 임포트 합니다.

// React의 상태 관리 훅 중 하나인 'useReducer'를 가져옵니다.
// 'useReducer'는 'useState'보다 복잡한 상태 로직을 다룰 때 유용하며, Redux와 유사한 패턴을 따릅니다.
import { useReducer } from 'react';

  function countReducer(
  
  ) {}

 

펑션 카운트리듀서를 카운트 변수 위에 추가 합니다.

기능은 일단 비워 둡니다.


const [count, countDispatch] = useReducer(countReducer, 0);

 

카운트를 유즈리듀서로 업그레이드 합니다.

카운트디스패치는 리듀서에 액션을 전달만 하는 아이입니다.

유즈리듀서 파라미터 1번은 위에서 작성한 펑션, 2번은 초기값입니다.

  // 'useReducer' 훅을 사용하여 'count' 상태와 'countDispatch' 함수를 선언합니다.
  // 첫 번째 인자로는 'countReducer' 함수를, 두 번째 인자로는 'count'의 초기값(0)을 전달합니다.
  // 'count'는 현재 상태 값이며, 'countDispatch'는 리듀서 함수에 액션을 전달하는 함수입니다.
  const [count, countDispatch] = useReducer(countReducer, 0);

  function down() {
    countDispatch("DOWN");
  }
  function reset() {
    countDispatch("RESET");
  }
  function up() {
    countDispatch("UP");
  }

 

셋카운트를 카운트디스패치로 변경합니다.

카운트디스패치 파라미터를 "액션"이라고 합니다.

위 세가지 펑션은 디테일한 기능을 수행 하지 않습니다.

이 펑션은 리듀서 콜만 하는 역할 입니다.

중요한 일은 리듀서가 담당할 것입니다.

이렇게 카운트디스패치가 리듀서에게 액션이나 데이터를 전달하는 행위 그 자체를 "디스패치"라고 합니다.

  // 'count' 값을 감소시키는 함수입니다. 'DOWN' 액션을 디스패치합니다.
  function down() {
    countDispatch('DOWN');
  }
  
  // 'count' 값을 0으로 초기화하는 함수입니다. 'RESET' 액션을 디스패치합니다.
  function reset() {
    countDispatch('RESET');
  }
  
  // 'count' 값을 증가시키는 함수입니다. 'UP' 액션을 디스패치합니다.
  function up() {
    countDispatch('UP');
  }

function countReducer(oldCount, action) {
    
  }

 

카운트리듀서 파라미터를 추가 합니다.

1번 파라미터는 기존밸류입니다.

2번 파라미터는 액션밸류입니다.

이렇게 파라미터를 세팅하고 카운트디스패치 콜 받을 준비를 합니다.


  function countReducer(oldCount, action) {
    if (action === "UP") {
      return oldCount + 1;
    } else if (action === "DOWN") {
      return oldCount - 1;
    } else if (action === "RESET") {
      return 0;
    }
    return oldCount; 
  }

 

기존 연산펑션에 있던 연산을 가져 옵니다.

액션에 따라 달라지는 엘스이프문을 추가 합니다.

결과를 카운트에 리턴합니다.

그러면 펑션앱이 리렌더링 됩니다.

혹시 모를 예외처리를 위해 엘스 대신 마지막에 올드카운트를 리턴하는 센스도 추천 합니다.

  // 'countReducer' 함수는 상태(oldCount)와 액션(action)을 인자로 받아 새로운 상태를 반환합니다.
  // 이 함수는 'useReducer' 훅에서 상태를 업데이트하는 로직을 담당합니다.
  function countReducer(oldCount, action) {
    if (action === 'UP') {
      // 액션이 'UP'이면 이전 값에 1을 더합니다.
      return oldCount + 1;
    } else if (action === 'DOWN') {
      // 액션이 'DOWN'이면 이전 값에 1을 뺍니다.
      return oldCount - 1;
    } else if (action === 'RESET') {
      // 액션이 'RESET'이면 값을 0으로 초기화합니다.
      return 0;
    }
    // 정의되지 않은 액션의 경우, 현재 상태를 그대로 반환합니다. (안정성을 위해 기본값 처리 권장)
    return oldCount; 
  }

Tip

oldCount 파라미터는 어디서 값을 넘겨 받았을까?

 

oldCount 값은 리액트(React)가 내부적으로 관리하고 있다가 자동으로 넘겨주는 현재의 상태 값입니다.

조금 더 자세히 풀어서 설명해 드릴게요.


1. useReducer의 동작 원리

useReducer를 선언할 때 우리는 리액트에게 이렇게 약속을 합니다.

"리액트야, 앞으로 count라는 상태는 countReducer라는 함수를 통해서만 변경할게. 그리고 시작 값은 0으로 해줘."

JavaScript
 
const [count, countDispatch] = useReducer(countReducer, 0);

2. oldCount는 어디서 오는가?

우리가 countDispatch('UP')를 호출하면, 리액트는 미리 등록해둔 countReducer 함수를 실행합니다.

이때 리액트는 함수에 두 개의 인자를 보냅니다.

  1. 첫 번째 인자 (oldCount): 리액트가 기억하고 있는 현재의 최신 상태 값을 넣어줍니다.
  2. 두 번째 인자 (action): 우리가 countDispatch('UP')를 호출할 때 괄호 안에 넣었던 값('UP')을 넣어줍니다.

3. 흐름 요약 (예시: 버튼을 눌렀을 때)

  1. 사용자: + 버튼 클릭 → up() 함수 실행.
  2. 코드: countDispatch('UP') 호출.
  3. 리액트: "오, count를 바꾸라고? 그럼 countReducer를 실행해야지!"
  4. 리액트: countReducer(현재값, 'UP') 형태로 함수를 실행. (여기서 현재값이 질문하신 oldCount에 자동으로 대입됩니다.)
  5. 함수 내부: oldCount + 1을 계산해서 리턴.
  6. 리액트: 리턴받은 새로운 값을 새로운 count로 업데이트하고 화면을 다시 그림.

핵심 포인트

직접 countReducer를 호출하는 것이 아니라, dispatch를 통해 리액트에게 요청만 하면 리액트가 알아서 현재 값을 꺼내 oldCount에 넣어준다는 점이 핵심입니다.


test

카운트가 잘 작동하는지 체크합니다.


Completion

import { useState } from 'react';
import reactLogo from './assets/react.svg';
import viteLogo from '/vite.svg';
import './App.css';
import { useReducer } from 'react';

export default function App() {
  function countReducer(oldCount, action) {
    if (action === 'UP') {
      return oldCount + 1;
    } else if (action === 'DOWN') {
      return oldCount - 1;
    } else if (action === 'RESET') {
      return 0;
    }
    return oldCount;
  }

  const [count, countDispatch] = useReducer(countReducer, 0);

  function down() {
    countDispatch('DOWN');
  }
  function reset() {
    countDispatch('RESET');
  }
  function up() {
    countDispatch('UP');
  }

  return (
    <div>
      <input type="button" value="-" onClick={down} />
      <input type="button" value="0" onClick={reset} />
      <input type="button" value="+" onClick={up} />
      <span>{count}</span>
    </div>
  );
}


인풋 유아이를 추가 합니다.


import { useReducer, useState } from "react";

 

코드 살짝 정리 합니다.fun


  const [number, setNumber] = useState(1);

 

펑션앱 바로 아래에 넘버를 유즈스테이트로 초기화 합니다.

초기값도 살짝 지정해 줍니다.

  // 'useState' 훅을 사용하여 'number'라는 상태 변수와 이를 업데이트하는 'setNumber' 함수를 선언합니다.
  // 'number'의 초기값은 1로 설정됩니다. 이 값은 텍스트 입력 필드와 연결될 예정입니다.
  const [number, setNumber] = useState(1);

function changeNumber() {
    
  }

 

펑션앱 리턴 바로 위에 체인지넘버펑션을 추가합니다.


      <input type="text" value={number} onChange={changeNumber} />

 

카운트 위에 체인지넘버 유아이를 추가 합니다.

이제부터 인풋 데이터가 변경될때마다 펑션콜 해서 넘버데이터가 업데이트 됩니다.

      {/* 'number' 상태의 값을 표시하고 사용자가 값을 입력할 수 있는 텍스트 입력 필드입니다.
          값이 변경될 때마다 changeNumber 함수가 호출되어 'number' 상태를 업데이트합니다. */}
      <input type="text" value={number} onChange={changeNumber} />

  function changeNumber(event) {
    setNumber(Number(event.target.value));
  }

 

인풋데이터 변경을 감지하면 이 평션이 콜 받습니다.

인풋으로 받은 데이터를 넘버타입으로 컨버팅합니다.

그 데이터가 새로운 데이터로 갱신 됩니다.

그러면 리액트가 이를 감지 합니다.

그러면 펑션앱이 실행되고 리렌더링 되어 인풋에 출력됩니다.

카운트와 연동은 다음 스텝에서 진행 합니다.

  // 텍스트 입력 필드의 값이 변경될 때 호출되는 함수입니다.
  // 입력된 값을 'number' 상태에 업데이트합니다. 이때 `Number()`를 사용하여 문자열을 숫자로 변환합니다.
  function changeNumber(event) {
    setNumber(Number(event.target.value));
  }

test

유아이를 체크 합니다.


Completion

import reactLogo from './assets/react.svg';
import viteLogo from '/vite.svg';
import './App.css';
import { useReducer, useState } from 'react';

export default function App() {
  const [number, setNumber] = useState(1);

  function countReducer(oldCount, action) {
    if (action === 'UP') {
      return oldCount + 1;
    } else if (action === 'DOWN') {
      return oldCount - 1;
    } else if (action === 'RESET') {
      return 0;
    }
    return oldCount;
  }
  const [count, countDispatch] = useReducer(countReducer, 0);

  function down() {
    countDispatch('DOWN');
  }
  function reset() {
    countDispatch('RESET');
  }
  function up() {
    countDispatch('UP');
  }
  function changeNumber(event) {
    setNumber(Number(event.target.value));
  }
  return (
    <div>
      <input type="button" value="-" onClick={down} />
      <input type="button" value="0" onClick={reset} />
      <input type="button" value="+" onClick={up} />
      <input type="text" value={number} onChange={changeNumber} />
      <span>{count}</span>
    </div>
  );
}


유저가 입력한 넘버와 연동 하는 카운트 기능을 구현합니다.


  function down() {
    countDispatch({ type: "DOWN", number: number });
  }
  function reset() {
    countDispatch({ type: "RESET", number: number });
  }
  function up() {
    countDispatch({ type: "UP", number: number });
  }

 

펑션 다운/리셋/업은 액션과 넘버데이터에만 집중하겠습니다.

그러기 위해 카운트디스패치 파라미터를 오브젝트로 변경합니다.

왜냐하면 파라미터가 복수로 변경되기 때문입니다.

 

여기서 넘버는 인풋 넘버를 바라 봅니다.

 

넘버데이터는 카운트디스패치로 콘트롤 하겠습니다.

왜냐하면 넘버데이터는 핵심연산에 해당되지 않기 때문 입니다.

리듀서는 핵심만 처리하기로 합니다.

그러므로 액션과 데이터는 여기서 처리 합니다.

 

즉, 펑션 카운트리듀서는 코어기능에만 집중합니다.

  // 'count' 값을 감소시키는 함수입니다.
  // 'countDispatch'를 통해 `{ type: 'DOWN', number: number }` 형태의 액션 객체를 전달합니다.
  // 이 액션 객체의 'number' 값은 현재 input 필드의 값입니다.
  function down() {
    countDispatch({ type: 'DOWN', number: number });
  }
  
  // 'count' 값을 0으로 재설정하는 함수입니다.
  // 'countDispatch'를 통해 `{ type: 'RESET', number: number }` 형태의 액션 객체를 전달합니다.
  // RESET의 경우 'number' 값은 리듀서 내에서 사용되지 않지만, 액션 객체의 일관된 형태를 유지합니다.
  function reset() {
    countDispatch({ type: 'RESET', number: number });
  }
  
  // 'count' 값을 증가시키는 함수입니다.
  // 'countDispatch'를 통해 `{ type: 'UP', number: number }` 형태의 액션 객체를 전달합니다.
  // 이 액션 객체의 'number' 값은 현재 input 필드의 값입니다.
  function up() {
    countDispatch({ type: 'UP', number: number });
  }

  function countReducer(oldCount, action) {
    if (action.type === "UP") {
      return oldCount + action.number;
    } else if (action.type === "DOWN") {
      return oldCount - action.number;
    } else if (action.type === "RESET") {
      return 0;
    }
    return oldCount;
  }

 

위 코드에서 액션에 타입이 붙었습니다.

옵션도 두가지로 늘었습니다.

그렇다면 카운트리듀서도 개선해야 합니다.

엘스이프 코드를 오브젝트 데이터 맞춤형으로 업그레이드 합니다.

  // 'countReducer' 함수는 'useReducer' 훅에서 사용할 리듀서 함수입니다.
  // 이 함수는 현재 상태(oldCount)와 '액션 객체'(action)를 인자로 받아 새로운 상태를 계산하여 반환합니다.
  // 액션 객체는 일반적으로 'type' 속성을 포함하여 어떤 종류의 작업인지 명시합니다.
  function countReducer(oldCount, action) {
    // 액션 객체의 'type'이 'UP'인 경우입니다.
    if (action.type === 'UP') {
      // 이전 값에 액션 객체의 'number' 속성 값을 더하여 반환합니다.
      return oldCount + action.number;
    }
    // 액션 객체의 'type'이 'DOWN'인 경우입니다.
    else if (action.type === 'DOWN') {
      // 이전 값에서 액션 객체의 'number' 속성 값을 빼서 반환합니다.
      return oldCount - action.number;
    }
    // 액션 객체의 'type'이 'RESET'인 경우입니다.
    else if (action.type === 'RESET') {
      // 값을 0으로 초기화하여 반환합니다.
      return 0;
    }
    // 정의되지 않은 액션이 들어오면 현재 상태를 그대로 반환하여 안정성을 유지합니다.
    return oldCount;
  }

test

 

인풋 숫자만큼 카운트가 늘어나는지 체크 합니다.


Completion

import reactLogo from './assets/react.svg';
import viteLogo from '/vite.svg';
import './App.css';
import { useReducer, useState } from 'react';

export default function App() {
  const [number, setNumber] = useState(1);

  function countReducer(oldCount, action) {
    if (action.type === 'UP') {
      return oldCount + action.number;
    } else if (action.type === 'DOWN') {
      return oldCount - action.number;
    } else if (action.type === 'RESET') {
      return 0;
    }
    return oldCount;
  }

  const [count, countDispatch] = useReducer(countReducer, 0);

  function down() {
    countDispatch({ type: 'DOWN', number: number });
  }
  function reset() {
    countDispatch({ type: 'RESET', number: number });
  }
  function up() {
    countDispatch({ type: 'UP', number: number });
  }

  function changeNumber(event) {
    setNumber(Number(event.target.value));
  }

  return (
    <div>
      <input type="button" value="-" onClick={down} />
      <input type="button" value="0" onClick={reset} />
      <input type="button" value="+" onClick={up} />
      <input type="text" value={number} onChange={changeNumber} />
      <span>{count}</span>
    </div>
  );
}

Commnet ver

// 프로젝트의 'assets' 폴더에 있는 'react.svg' 이미지를 불러옵니다.
// 현재 코드에서는 직접 사용되지는 않습니다.
import reactLogo from './assets/react.svg';
// 루트 경로에 있는 'vite.svg' 이미지를 불러옵니다.
// 이 이미지 또한 현재 코드에서는 직접 사용되지 않습니다.
import viteLogo from '/vite.svg';
// 이 컴포넌트의 스타일을 정의하는 'App.css' 파일을 불러와 적용합니다.
import './App.css';
// React의 상태 관리 훅인 'useReducer'와 'useState'를 가져옵니다.
// 'useState'는 간단한 상태 관리에, 'useReducer'는 복잡한 상태 로직 관리에 사용됩니다.
import { useReducer, useState } from 'react';

// 'App'이라는 이름의 함수형 컴포넌트를 정의하고 기본 내보내기로 설정합니다.
// 이 컴포넌트가 애플리케이션의 주 진입점 역할을 합니다.
export default function App() {
  // 'useState' 훅을 사용하여 'number'라는 상태 변수와 이를 업데이트하는 'setNumber' 함수를 선언합니다.
  // 'number'의 초기값은 1로 설정됩니다. 이 값은 텍스트 입력 필드와 연결되어 카운트 증가/감소량으로 사용될 예정입니다.
  const [number, setNumber] = useState(1);

  // 'countReducer' 함수는 'useReducer' 훅에서 사용할 리듀서 함수입니다.
  // 이 함수는 현재 상태(oldCount)와 '액션 객체'(action)를 인자로 받아 새로운 상태를 계산하여 반환합니다.
  // 액션 객체는 일반적으로 'type' 속성을 포함하여 어떤 종류의 작업인지 명시합니다.
  function countReducer(oldCount, action) {
    // 액션 객체의 'type'이 'UP'인 경우입니다.
    if (action.type === 'UP') {
      // 이전 값에 액션 객체의 'number' 속성 값을 더하여 반환합니다.
      return oldCount + action.number;
    }
    // 액션 객체의 'type'이 'DOWN'인 경우입니다.
    else if (action.type === 'DOWN') {
      // 이전 값에서 액션 객체의 'number' 속성 값을 빼서 반환합니다.
      return oldCount - action.number;
    }
    // 액션 객체의 'type'이 'RESET'인 경우입니다.
    else if (action.type === 'RESET') {
      // 값을 0으로 초기화하여 반환합니다.
      return 0;
    }
    // 정의되지 않은 액션이 들어오면 현재 상태를 그대로 반환하여 안정성을 유지합니다.
    return oldCount;
  }
  
  // 'useReducer' 훅을 사용하여 'count' 상태와 'countDispatch' 함수를 선언합니다.
  // 'countReducer' 함수를 리듀서로 사용하고, 'count'의 초기값은 0으로 설정합니다.
  // 'count'는 현재 카운터 값이며, 'countDispatch'는 리듀서에 '액션 객체'를 전달하여 'count'를 업데이트하는 함수입니다.
  const [count, countDispatch] = useReducer(countReducer, 0);

  // 'count' 값을 감소시키는 함수입니다.
  // 'countDispatch'를 통해 `{ type: 'DOWN', number: number }` 형태의 액션 객체를 전달합니다.
  // 이 액션 객체의 'number' 값은 현재 input 필드의 값입니다.
  function down() {
    countDispatch({ type: 'DOWN', number: number });
  }
  
  // 'count' 값을 0으로 재설정하는 함수입니다.
  // 'countDispatch'를 통해 `{ type: 'RESET', number: number }` 형태의 액션 객체를 전달합니다.
  // RESET의 경우 'number' 값은 리듀서 내에서 사용되지 않지만, 액션 객체의 일관된 형태를 유지합니다.
  function reset() {
    countDispatch({ type: 'RESET', number: number });
  }
  
  // 'count' 값을 증가시키는 함수입니다.
  // 'countDispatch'를 통해 `{ type: 'UP', number: number }` 형태의 액션 객체를 전달합니다.
  // 이 액션 객체의 'number' 값은 현재 input 필드의 값입니다.
  function up() {
    countDispatch({ type: 'UP', number: number });
  }

  // 텍스트 입력 필드의 값이 변경될 때 호출되는 함수입니다.
  // 이벤트 객체에서 현재 입력된 값을 가져와 'number' 상태에 업데이트합니다.
  // 이때 `Number()`를 사용하여 문자열로 들어온 값을 숫자로 변환합니다.
  function changeNumber(event) {
    setNumber(Number(event.target.value));
  }

  // 컴포넌트가 렌더링할 UI를 정의하는 JSX를 반환합니다.
  return (
    // 전체 요소를 감싸는 div 컨테이너입니다.
    <div>
      {/* '하향(-)' 기능을 수행하는 버튼입니다. 클릭 시 down 함수가 호출됩니다. */}
      <input type="button" value="-" onClick={down} />
      {/* '초기화(0)' 기능을 수행하는 버튼입니다. 클릭 시 reset 함수가 호출됩니다. */}
      <input type="button" value="0" onClick={reset} />
      {/* '상향(+)' 기능을 수행하는 버튼입니다. 클릭 시 up 함수가 호출됩니다. */}
      <input type="button" value="+" onClick={up} />
      {/* 'number' 상태의 값을 표시하고 사용자가 값을 입력할 수 있는 텍스트 입력 필드입니다.
          값이 변경될 때마다 changeNumber 함수가 호출되어 'number' 상태를 업데이트합니다. */}
      <input type="text" value={number} onChange={changeNumber} />
      {/* 현재 'count' 상태 변수의 값을 표시하는 span 태그입니다. */}
      <span>{count}</span>
    </div>
  );
}


출처

https://wikibook.co.kr/react-rev-ebook/

 

생활코딩! React 리액트 프로그래밍 (개정판) (ebook): 처음 프로그래밍을 시작하는 입문자의 눈높이

세상에서 리액트를 가장 쉽게 설명한 입문서! 생활코딩은 일반인에게 프로그래밍을 알려주는 것을 목적으로 하는 비영리 교육 활동입니다. 이 책은 생활코딩에서 제공하는 수업 가운데 리액트

wikibook.co.kr