교육 (Today I Learned)/Hanaro

[Hanaro] 24일차 / React (Hooks- useState, useRef)

Bay Im 2024. 2. 20. 09:27

02 React Hooks

  • React의 상태 및 life-cycle 관리
    • 상태 관리 Hooks
      • useState
      • useContext (createContext)
      • useReducer
    • 시점 Hooks
      • useLayoutEffect (render 후)
      • useEffect (pain 후)
    • 메모화 Hooks
      • useMemo
      • useCallback
      • memo
    • 그 외 Hooks
      • useRef, useImperativeHandle
      • useDebugValue, useId
  • Hooks의 3 원칙
    • 컴포넌트 영역 안에서만 작동
      • 함수 컴포넌트, 커스텀 훅 내부에서만 호출해야 한다.
    • 기능을 여러 훅으로 나누면 좋다.
      • 나누어 있어도 컴포넌트에서 한번에 순차 호출
      • 함수형 컴포넌트→ 함수→ 기능 단위 분리→ 가독성→ 테스트 및 유지보수에 유리
    • 최상위 레이어에서만 호출해야 한다.
      • 블록 내부에서는 호출 불가
  • React Hooks - useState
    • useState란
      • state란 컴포넌트가 가질 수 있는 상태를 말한다.
      • 순수 함수→ 컴포넌트 내에서 변경될 수 있는 값
      • 해당 상태를 소유하지 않은 컴포넌트에서는 props
      • 변수는 read-only이므로 변경은 setter를 이용한다.
      • 변수가 객체(참조)형이면 spread 연산자로 사본을 만들어 setter에서는 값 수신
    • import
      • useState 사용하기 위해서 import 해야한다.
      • import { useState } from ‘react’;
    • 변수 선언
      • const [state, setState] = useState<타입>(초값이나 초기화함수);
    • 변수 재선언
      • state 값 변경 시 setter ㅎ함수 호출 후 변경될 값을 넣어줘야 한다.
      • setState(변경될값);
    • 변수 출력
      • 예시 <input type='text' value={state} onChange={setState사용함수} />
    • 예시
      • 선언, 재선언, 출력 예시
      import { useState } from 'react';  // useState import
      
      export type LoginUser = { id: number; name: string };
      export type Cart = { id: number; name: string; price: number };
      export type Session = {
        loginUser: LoginUser | null;
        cart: Cart[];
      };
      
      function App() {
      	// 변수 선언 
      	const [count, setCount] = useState(0);
        const [session, setSession] = useState<Session>(SampleSession);
      	
      	// 변수 재선언
      	const plusCount = () => setCount((prevCount) => prevCount + 1);
      	const login = (id: number, name: string) => {
          setSession({ ...session, loginUser: { id, name } });
        };
        const logout = () => {
          setSession({ ...session, loginUser: null });
        };
      
      	// 변수 출력
      	return (
      	<div>
      		<span>count: {count}</span>
      		<span>session: {session}</span>
      	</div>
      	);
      }
      
      • 변수 재선언(event 함수) 예시
      import { ChangeEvent, useState } from 'react';
      
      const CITIES = ['서울', '대전', '대구', '부산', '창원'];
      	
      export default function Sample() {
      	// 변수 선언 
        const [nickname, setNickname] = useState('HONG');
        const [address, setAddress] = useState('서울');
        const [age, setAge] = useState('20');
        
      	// 변수 재선언 함수 
        const changeNickname = (e: ChangeEvent<HTMLInputElement>) =>
          setNickname(e.currentTarget.value);
      
        const changeAge = (e: ChangeEvent<HTMLInputElement>) =>
          setAge(e.currentTarget.value);
      
        return (
          <>
            <div>
              <h5>
      					// 변수 출력 
                NickName: {nickname}({age}세) - {address}
              </h5>
              <input type='text' value={nickname} onChange={changeNickname} />
              <input type='number' value={age} onChange={changeAge} />
              <input
                type='text'
                value={address}
      					// 변수 재선언
                onChange={(e) => setAddress(e.currentTarget.value)}
              />
      				// 변수 재선언
              <select onChange={(e) => setAddress(e.currentTarget.value)}>
                {CITIES.map((item) => (
                  <option key={item} value={item}>
                    {item}
                  </option>
                ))}
              </select>
            </div>
          </>
        );
      }
      
  • React Hooks - useRef
    • useRef란
      • 직접 DOM에 접근할 때 또는 값을 담을 때 사용
      • .current 프로퍼티로 전달된 인자로 초기화된 변경 가능한 ref 객체를 반환 (ref는 reference 참조!)
      • onChange와 같은 무거운 Event Handler를 사용하지 않아도 된다.
      • useRef를 이용하여 DOM에 접근하면 값이 변경되어도 불필요한 re-rendering을 하지 않는다. (state에 담으면 변경될 때마다 re-rendering)
    • import
      • import { useRef } from ‘react;
    • 변수 선언
      • const 변수명 = useRef(초기값);
      • useRef는 변수명에 초기값을 적는 식으로 생성한다.
      • {current: 초기값} 을 지닌 객체가 반환된다. 값 변경도 current를 이용하여 변경
    • 변수 출력
      • 예시 <span ref={변수명}>
      • <input type='text' ref={변수명} />
      • <MyComponent ref={변수명} />
    • 해당 DOM의 속성
      • 변수명.current.value
      • 변수명.current.focus()
    • 예시
      • Login 예시
      import { FormEvent, useRef } from 'react';
      
      type Props = {
        login: (id: number, name: string) => void;
      };
      
      export const Login = ({ login }: Props) => {
      	// 변수 선언 
        const idRef = useRef<HTMLInputElement | null>(null);
        const nameRef = useRef<HTMLInputElement | null>(null);
      
        const makeLogin = (e: FormEvent<HTMLFormElement>) => {
          e.preventDefault(); // submit 기본 기능을 무력화!
      
          console.log(`makeLogin#${idRef.current?.value}#`);
      
          if (!idRef.current || !idRef.current.value) {
            alert('User ID를 입력하세요!');
            idRef.current?.focus();
            return;
          } else if (!nameRef.current?.value) {
            alert('User Name를 입력하세요!');
            idRef.current?.focus();
            return;
          }
      		
      		// 속성 
          const id = idRef.current.value;
          const name = nameRef.current.value;
      
          login(+id, name);
        };
      
        return (
          <>
            <form onSubmit={makeLogin}>
              <div>
                <span style={{ marginRight: '1em' }}>LoginID:</span>
                <input type='number' ref={idRef} />
              </div>
              <div>
                LoginName:
                {/* <input type='text' onChange={(e) => setName(e.currentTarget.value)} /> */}
                <input type='text' ref={nameRef}></input>
              </div>
              <button type='submit'>Sign-in</button>
            </form>
          </>
        );
      };