π Mutation Observer μ€μ©: 무ν 루νμ μ±λ₯ μ ν, κ·Έλ¦¬κ³ μμΈ‘ λΆκ°λ₯ν λμ
Summary
Mutation Observerλ₯Ό λΆμ£Όμνκ² μ¬μ©νλ©΄ 무ν 루ν, μ±λ₯ μ ν, μμΈ‘ λΆκ°λ₯ν λμμ μ΄λν μ μμ΅λλ€. μν κ΄λ¦¬, λΉλκΈ° μ²λ¦¬, κ°μ λ²μ μ΅μν, disconnect() νΈμΆ λ±μ ν΅ν΄ μ΄λ¬ν λ¬Έμ λ₯Ό ν΄κ²°ν΄μΌ ν©λλ€.
Why Wrong?
Mutation Observerλ DOM λ³κ²½μ κ°μ§νλ κ°λ ₯ν APIμ΄μ§λ§, μλͺ» μ¬μ©νλ©΄ 무ν 루ν, μ±λ₯ μ ν, μμΈ‘ λΆκ°λ₯ν λμμ μ λ°ν μ μμ΅λλ€. νΉν μ½λ°± ν¨μ λ΄μμ κ°μ§ λμ DOMμ μ§μ λ³κ²½νλ κ²½μ°, Mutation Observerκ° λ€μ νΈλ¦¬κ±°λμ΄ λ¬΄ν 루νμ λΉ μ§ μνμ΄ μμ΅λλ€. λν, νμ μ΄μμ λμ λ²μμ DOM λ³κ²½μ κ°μνκ±°λ, λΆνμνκ² λ§μ Mutation Observer μΈμ€ν΄μ€λ₯Ό μμ±νλ κ²½μ° μ±λ₯ μ νλ₯Ό μ΄λν μ μμ΅λλ€. μ΄λ λΈλΌμ°μ μ λ λλ§ νμ΄νλΌμΈμ λ°©ν΄νκ³ μ¬μ©μ κ²½νμ μ νμν΅λλ€.
How to Fix?
Mutation Observer μ½λ°± ν¨μ λ΄μμ κ°μ§ λμ DOMμ μ§μ λ³κ²½νλ κ²μ νΌν΄μΌ ν©λλ€. μν κ΄λ¦¬ λΌμ΄λΈλ¬λ¦¬λ₯Ό νμ©νμ¬ DOM λ³κ²½μ μ λ°νλ μνλ₯Ό μ
λ°μ΄νΈνκ±°λ, λΉλκΈ°μ μΌλ‘ DOMμ λ³κ²½νλ λ°©μμΌλ‘ 무ν 루νλ₯Ό λ°©μ§ν μ μμ΅λλ€. λν, κ°μ λ²μλ₯Ό μ΅μννκ³ , νμν Mutation Observer μΈμ€ν΄μ€λ§ μμ±νμ¬ μ±λ₯μ μ΅μ νν΄μΌ ν©λλ€. κ°μλ₯Ό μ€λ¨ν΄μΌ νλ μμ μ disconnect() λ©μλλ₯Ό νΈμΆνμ¬ λ©λͺ¨λ¦¬ λμλ₯Ό λ°©μ§νλ κ²λ μ€μν©λλ€.
Before Code (Bad)
import React, { useEffect, useRef } from 'react';
function BadComponent() {
const elementRef = useRef(null);
useEffect(() => {
const observer = new MutationObserver((mutationsList) => {
mutationsList.forEach(() => {
// β μ§μ DOM λ³κ²½ -> 무ν 루ν κ°λ₯μ±!
elementRef.current.textContent = 'DOM Updated!';
});
});
observer.observe(elementRef.current, { characterData: true, subtree: true, childList: true });
return () => observer.disconnect();
}, []);
return <div ref={elementRef}>Initial Text</div>;
}
export default BadComponent;After Code (Good)
import React, { useState, useEffect, useRef } from 'react';
function GoodComponent() {
const [text, setText] = useState('Initial Text');
const elementRef = useRef(null);
useEffect(() => {
const observer = new MutationObserver((mutationsList) => {
mutationsList.forEach(() => {
// DOM λ³κ²½ κ°μ§ ν μν μ
λ°μ΄νΈ
setText('DOM Changed!');
});
});
observer.observe(elementRef.current, { characterData: true, subtree: true, childList: true });
return () => observer.disconnect();
}, []);
return <div ref={elementRef}>{text}</div>;
}
export default GoodComponent;