본문 바로가기
카테고리 없음

React.js 정리 1

by letsDoDev 2025. 11. 17.

# 디바운스

인풋에서 값 입력될 때 특정 시간동안 발생한 change 이벤트의 마지막 이벤트에만 반응해서 핸들러로 인풋아이템에 입력된 값 setState 하기

import React, { useState, useCallback } from 'react';

// 디바운스 함수 정의
function debounce(func, delay) {
  let timer;
  return function (...args) {
    clearTimeout(timer);
    timer = setTimeout(() => {
      func.apply(this, args);
    }, delay);
  };
}

export default function DebouncedInput() {
  const [valueState, setValueState] = useState('');

  // 디바운스된 setValueState 함수 생성
  const debouncedSetValue = useCallback(
    debounce((val) => {
      setValueState(val);
    }, 500), // 500ms 지연
    []
  );

  // input의 onChange 핸들러
  const handleChange = (e) => {
    debouncedSetValue(e.target.value);
  };

  return (
    <div>
      <input type="text" onChange={handleChange} placeholder="입력해보세요" />
      <p>디바운스된 값: {valueState}</p>
    </div>
  );
}

 

# mutaion
case 1. 특정 dom 안에 특정 text 추가되면 감지해서 글자 색 변경하기

<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8" />
  <title>MutationObserver 예제</title>
</head>
<body>
  <div id="container">
    <p>기존 문장입니다.</p>
  </div>
  <button id="add">새 문장 추가</button>

  <script>
    const container = document.getElementById('container');

    // MutationObserver 콜백 함수
    const observer = new MutationObserver((mutationsList) => {
      for (const mutation of mutationsList) {
        if (mutation.type === 'childList') {
          mutation.addedNodes.forEach((node) => {
            if (node.nodeType === Node.ELEMENT_NODE) {
              // 새로 추가된 요소에 인라인 스타일 적용
              node.style.color = 'red';
            } else if (node.nodeType === Node.TEXT_NODE) {
              // 텍스트 노드만 추가된 경우 span으로 감싸기
              const span = document.createElement('span');
              span.textContent = node.textContent;
              span.style.color = 'red';
              node.parentNode.replaceChild(span, node);
            }
          });
        }
      }
    });

    // 감시 시작
    observer.observe(container, {
      childList: true,
      subtree: true,
    });

    // 버튼 클릭 시 새 요소 추가
    document.getElementById('add').addEventListener('click', () => {
      const newP = document.createElement('p');
      newP.textContent = '새로 추가된 문장입니다.';
      container.appendChild(newP);
    });
  </script>
</body>
</html>
childList 자식 노드의 추가/삭제 감지
attributes 속성(attribute)의 변경 감지
characterData 텍스트 노드의 내용 변경 감지
subtree 하위 모든 자손 노드까지 감시 확장
attributeFilter 감시할 속성 이름 배열 지정
attributeOldValue 변경 전 속성 값도 함께 제공
characterDataOldValue 변경 전 텍스트 값도 함께 제공

 

case 2. 특정 element 의 class명 변경될 때, 콘솔 찍기

<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8" />
  <title>MutationObserver 속성 감지</title>
  <style>
    .highlight {
      background-color: yellow;
    }
  </style>
</head>
<body>
  <div id="target">감시 대상입니다</div>
  <button id="change">클래스 변경</button>

  <script>
    const targetNode = document.getElementById('target');

    // MutationObserver 콜백
    const observer = new MutationObserver((mutationsList) => {
      mutationsList.forEach((mutation) => {
        if (mutation.type === 'attributes') {
          console.log('속성이 변경되었습니다!');
          console.log('변경된 속성:', mutation.attributeName);
          console.log('현재 클래스:', targetNode.className);
        }
      });
    });

    // 감시 시작
    observer.observe(targetNode, {
      attributes: true // 속성 변경 감지
    });

    // 버튼 클릭 시 클래스 변경
    document.getElementById('change').addEventListener('click', () => {
      targetNode.classList.toggle('highlight');
    });
  </script>
</body>
</html>

# useRef 로 부모 컴포넌트에서 자식 컴포넌트 state 값 변경시키기, 자식 컴포넌트의 함수 실행시키기

- 자식 컴포넌트

import React, { useState, useImperativeHandle, forwardRef } from 'react';

const ChildComponent = forwardRef((props, ref) => {
  const [text, setText] = useState('초기값');

  // 부모에서 접근 가능한 함수 정의
  useImperativeHandle(ref, () => ({
    updateText(newText) {
      setText(newText);
    },
    resetText() {
      setText('초기값');
    }
  }));

  return <div>자식 상태: {text}</div>;
});

export default ChildComponent;

 

- 부모 컴포넌트

import React, { useRef } from 'react';
import ChildComponent from './ChildComponent';

export default function ParentComponent() {
  const childRef = useRef();

  const handleUpdate = () => {
    childRef.current?.updateText('부모가 변경한 값');
  };

  const handleReset = () => {
    childRef.current?.resetText();
  };

  return (
    <div>
      <ChildComponent ref={childRef} />
      <button onClick={handleUpdate}>자식 상태 변경</button>
      <button onClick={handleReset}>자식 상태 초기화</button>
    </div>
  );
}

# 부모 컴포넌트에서 손자 컴포넌트 함수 실행시키기 with CustomEvent

- 손자

import React, { useEffect } from 'react';

export default function GrandChild() {
  useEffect(() => {
    const handler = (e) => {
      console.log('손자 함수 실행됨!', e.detail);
      alert(`손자 함수 실행됨: ${e.detail}`);
    };

    // 커스텀 이벤트 리스너 등록
    window.addEventListener('runGrandChildFunction', handler);

    // 클린업
    return () => {
      window.removeEventListener('runGrandChildFunction', handler);
    };
  }, []);

  return <div>👶 손자 컴포넌트</div>;
}

 

- 자식

import React from 'react';
import GrandChild from './GrandChild';

export default function Child() {
  return (
    <div>
      <h3>👦 자식 컴포넌트</h3>
      <GrandChild />
    </div>
  );
}

- 부모

import React from 'react';
import Child from './Child';

export default function Parent() {
  const triggerGrandChild = () => {
    const event = new CustomEvent('runGrandChildFunction', {
      detail: '부모가 보낸 메시지',
    });
    window.dispatchEvent(event);
  };

  return (
    <div>
      <h2>👨 부모 컴포넌트</h2>
      <button onClick={triggerGrandChild}>손자 함수 실행시키기</button>
      <Child />
    </div>
  );
}