# 디바운스
인풋에서 값 입력될 때 특정 시간동안 발생한 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>
);
}