소프트웨어 기술(스타트업 위주)

React

React 정리 입니다. 구체적인 것은 공식문서내용이 더 구체적입니다. 개괄적인 개념을 설명드립니다.


React Guide

1. Rendering

1.1 Component Lifecycle

React 컴포넌트의 생명 주기는 크게 Mounting(생성), Updating(갱신), Unmounting(제거) 단계로 나뉩니다. 현업에서는 대부분 react 에서 hook 함수 useEffect를 이용해서 lifecycle을 다루긴 합니다.

생명 주기 메서드

  • componentDidMount (마운트 이후 실행)
  • componentDidUpdate (업데이트 이후 실행)
  • componentWillUnmount (언마운트 시 실행)

예제

import React, { Component } from 'react'

class LifecycleExample extends Component {
  componentDidMount() {
    console.log('Component Mounted!')
  }

  componentDidUpdate() {
    console.log('Component Updated!')
  }

  componentWillUnmount() {
    console.log('Component Will Unmount!')
  }

  render() {
    return <h1>React Lifecycle</h1>
  }
}

1.2 Lists and Keys

React에서 리스트를 렌더링할 때 map을 활용하고, 각 항목에는 고유한 key 값을 부여해야 합니다. react는 가상 DOM을 이용해 이전 상태와 새로운 상태를 비교하면서 변경된 부분만 실제 DOM에 반영합니다. 이 때 key를 할당하지 않으면 추가, 삭제, 이동된 DOM을 판단하기 어렵습니다.

성능도 당연히 느려지고 데이터 정합성도 떨어집니다. 그리고 고유 식별자로 인덱스 사용하지 않길 바랍니다. 고유한 현재 날짜라던지, 서버에서 내려오는 고유 PK 값으로 할당하길 바랍니다.

예제

const names = ['Alice', 'Bob', 'Charlie']

function NameList() {
  return (
    <ul>
      {names.map((name, index) => (
        <li key={index}>{name}</li>
      ))}
    </ul>
  )
}

1.3 Render Props

Render Props 패턴은 함수를 prop으로 전달하여 렌더링 로직을 공유하는 방식입니다.

예제

const MouseTracker = ({ render }) => {
  const [position, setPosition] = React.useState({ x: 0, y: 0 })

  const handleMouseMove = (event) => {
    setPosition({ x: event.clientX, y: event.clientY })
  }

  return <div onMouseMove={handleMouseMove}>{render(position)}</div>
}

export default function App() {
  return (
    <MouseTracker
      render={({ x, y }) => (
        <h1>
          Mouse position: {x}, {y}
        </h1>
      )}
    />
  )
}

1.4 Refs

refDOM 요소나 컴포넌트 인스턴스에 접근할 때 사용합니다. input 포커스, DOM 크기/위치 측정, 외부 라이러리 통합,, 애니메이션 직접 제어 같은 경우 ref를 많이 사용합니다. 일반적인 렌더링/상태 변경에서는 사용 지양합니다.

예제

import React, { useRef } from 'react'

function FocusInput() {
  const inputRef = useRef(null)

  const handleClick = () => {
    inputRef.current.focus()
  }

  return (
    <div>
      <input ref={inputRef} type="text" />
      <button onClick={handleClick}>Focus Input</button>
    </div>
  )
}

1.5 Events

React에서 이벤트는 CamelCase로 작성되며, 이벤트 핸들러는 함수로 정의합니다.

예제

function ClickHandler() {
  const handleClick = () => {
    alert('Button Clicked!')
  }

  return <button onClick={handleClick}>Click Me</button>
}

1.6 High Order Components (HOC)

고차 컴포넌트(HOC)는 컴포넌트를 감싸는 함수로, 재사용 가능한 로직을 분리할 때 사용합니다. 요즘엔 HOC보다 Custom Hook을 더 많이 쓰는 추세입니다. 하지만 UI도 감싸서 제어해야 하는 경우에는 여전히 HOC가 유용합니다.

예제

function withAuth(Component) {
  return function AuthComponent(props) {
    const isLoggedIn = checkLogin(); // 로그인 확인 로직

    if (!isLoggedIn) {
      return <div>로그인이 필요합니다.</div>;
    }

    return <Component {...props} />;
  };
}

// 사용 예시
const MyPage = () => <div>마이페이지</div>;
const MyPageWithAuth = withAuth(MyPage);

// <MyPageWithAuth /> 렌더링 시 로그인 체크됨

2. Functional Components

2.1 JSX

JSX는 JavaScript 내에서 XML 문법을 사용하여 UI를 표현하는 문법입니다.

예제

const Greeting = () => <h1>Hello, JSX!</h1>

2.2 Props vs State

  • Props: 부모에서 자식으로 전달되는 데이터 (불변)
  • State: 컴포넌트 내부에서 관리하는 데이터 (변경 가능)

예제

const Message = ({ text }) => <h1>{text}</h1>
function Counter() {
  const [count, setCount] = React.useState(0)
  return <button onClick={() => setCount(count + 1)}>Count: {count}</button>
}

2.3 Conditional Rendering

조건에 따라 다른 UI를 렌더링하는 기법입니다.

예제

const UserStatus = ({ isLoggedIn }) => (
  <h1>{isLoggedIn ? 'Welcome Back!' : 'Please Log In'}</h1>
)

3. Hooks

3.1 useState

const [count, setCount] = useState(0)

3.2 useEffect

useEffect(() => {
  console.log('Component Mounted')
  return () => console.log('Component Unmounted')
}, [])

3.3 useRef

const inputRef = useRef(null)
;<input ref={inputRef} />

3.4 useMemo

useMemo는 계산 비용이 큰 값을 "메모이제이션(memoization)"해서, 필요할 때만 다시 계산하게 해주는 Hook입니다.

function MyComponent({ number }) {
  const double = useMemo(() => {
    console.log("계산 중...");
    return number * 2;
  }, [number]);

  return <div>{double}</div>;
}

3.5 useReducer

const [state, dispatch] = useReducer(reducer, initialState)

3.6 useCallback

useCallback은 함수를 메모이제이션해서, 리렌더링 시에도 같은 함수를 재사용할 수 있게 해주는 Hook입니다. 함수버전 useMemo 라고 생각하시면 됩니다.

const memoizedCallback = useCallback(() => handleClick(id), [id])

3.7 useContext

const value = useContext(MyContext)

3.8 Custom Hook

훅 함수는 프로젝트 전반적으로 자주 사용되는 기능들을 따론 뺀 함수라고 생각하시면 됩니다.

예시를 들겠습니다.

  • 입력값 디바운싱
import { useEffect, useState } from "react";

export function useDebounce(value, delay = 300) {
  const [debounced, setDebounced] = useState(value);

  useEffect(() => {
    const handler = setTimeout(() => setDebounced(value), delay);
    return () => clearTimeout(handler);
  }, [value, delay]);

  return debounced;
}
  • 입력값 쓰로틀링
import { useEffect, useRef, useState } from "react";

export function useThrottle(value, delay = 300) {
  const [throttled, setThrottled] = useState(value);
  const lastRan = useRef(Date.now());

  useEffect(() => {
    const handler = setTimeout(() => {
      if (Date.now() - lastRan.current >= delay) {
        setThrottled(value);
        lastRan.current = Date.now();
      }
    }, delay - (Date.now() - lastRan.current));

    return () => clearTimeout(handler);
  }, [value, delay]);

  return throttled;
}
  • 간단한 API 호출
import { useEffect, useState } from "react";

export function useFetch(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    let isMounted = true;
    fetch(url)
      .then(res => res.json())
      .then(json => {
        if (isMounted) {
          setData(json);
          setLoading(false);
        }
      });
    return () => {
      isMounted = false;
    };
  }, [url]);

  return { data, loading };
}
  • localstorage 연동
import { useState } from "react";

export function useLocalStorage(key, initialValue) {
  const [storedValue, setStoredValue] = useState(() => {
    const item = localStorage.getItem(key);
    return item ? JSON.parse(item) : initialValue;
  });

  const setValue = value => {
    const valueToStore = value instanceof Function ? value(storedValue) : value;
    setStoredValue(valueToStore);
    localStorage.setItem(key, JSON.stringify(valueToStore));
  };

  return [storedValue, setValue];
}
  • 이전 값 기억
import { useEffect, useRef } from "react";

export function usePrevious(value) {
  const ref = useRef();

  useEffect(() => {
    ref.current = value;
  }, [value]);

  return ref.current;
}
  • 스크롤 위치 감지
import { useEffect, useState } from "react";

export function useScroll() {
  const [scrollY, setScrollY] = useState(window.scrollY);

  useEffect(() => {
    const handleScroll = () => setScrollY(window.scrollY);
    window.addEventListener("scroll", handleScroll);

    return () => window.removeEventListener("scroll", handleScroll);
  }, []);

  return scrollY;
}
  • true/false 상태 토글
import { useState } from "react";

export function useToggle(initialValue = false) {
  const [state, setState] = useState(initialValue);
  const toggle = () => setState(prev => !prev);

  return [state, toggle];
}

4. Routers

4.1 React Router

React Router를 사용하여 페이지 이동을 처리할 수 있습니다.

예제

import { BrowserRouter as Router, Route, Link } from 'react-router-dom'

function App() {
  return (
    <Router>
      <nav>
        <Link to="/home">Home</Link>
      </nav>
      <Route path="/home" component={HomePage} />
    </Router>
  )
}

이 문서에는 React의 주요 개념과 예제가 포함되어 있습니다. ✨

Previous
typescript
Next
next