useInsertionEffect
useInsertionEffect
๋ DOM ๋ณ๊ฒฝ ์ ์ ์คํ๋๋ useEffect
์ ๋ฒ์ ์
๋๋ค.
useInsertionEffect(setup, dependencies?)
๋ ํผ๋ฐ์ค
useInsertionEffect(setup, dependencies?)
useInsertionEffect
๋ฅผ ํธ์ถํ์ฌ DOM ๋ณ๊ฒฝ ์ ์ ์คํ์ผ์ ์ฃผ์
ํฉ๋๋ค:
import { useInsertionEffect } from 'react';
// CSS-in-JS ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์์์
function useCSS(rule) {
useInsertionEffect(() => {
// ... <style> ํ๊ทธ๋ฅผ ์ฌ๊ธฐ์์ ์ฃผ์
ํ์ธ์ ...
});
return rule;
}
๋งค๊ฐ๋ณ์
-
setup
: ์ดํํธ์ ๋ก์ง์ด ํฌํจ๋ ํจ์์ ๋๋ค. setup ํจ์๋ ์ ํ์ ์ผ๋ก cleanup ํจ์๋ฅผ ๋ฐํํ ์๋ ์์ต๋๋ค. ์ปดํฌ๋ํธ๊ฐ DOM์ ์ถ๊ฐ๋๊ธฐ ์ ์ React๋ setup ํจ์๋ฅผ ์คํํฉ๋๋ค. dependencies๊ฐ ๋ณ๊ฒฝ๋์ด ๋ค์ ๋ ๋๋งํ ๋๋ง๋ค React๋ ๋จผ์ ์ด์ ๊ฐ์ผ๋ก cleanup ํจ์(์ ๊ณตํ ๊ฒฝ์ฐ)๋ฅผ ์คํํ ๋ค์ ์ ๊ฐ์ผ๋ก setup ํจ์๋ฅผ ์คํํฉ๋๋ค. ์ปดํฌ๋ํธ๊ฐ DOM์์ ์ ๊ฑฐ๋๊ธฐ ์ ์ React๋ cleanup ํจ์๋ฅผ ํ ๋ฒ ๋ ์คํํฉ๋๋ค. -
์ ํ์ฌํญ
dependencies
:setup
์ฝ๋ ๋ด์์ ์ฐธ์กฐ๋ ๋ชจ๋ ๋ฐ์ํ ๊ฐ์ ๋ชฉ๋ก์ ๋๋ค. ๋ฐ์ํ ๊ฐ์๋ props, state, ๊ทธ๋ฆฌ๊ณ ์ปดํฌ๋ํธ ๋ณธ๋ฌธ์ ์ง์ ์ ์ธ๋ ๋ชจ๋ ๋ณ์์ ํจ์๊ฐ ํฌํจ๋ฉ๋๋ค. linter๊ฐ React์ฉ์ผ๋ก ์ค์ ๋ ๊ฒฝ์ฐ, ๋ชจ๋ ๋ฐ์ํ ๊ฐ์ด ์์กด์ฑ์ผ๋ก ์ฌ๋ฐ๋ฅด๊ฒ ์ง์ ๋์๋์ง ํ์ธํฉ๋๋ค. ์์กด์ฑ ๋ชฉ๋ก์๋ ์ผ์ ํ ์์ ํญ๋ชฉ์ด ์์ด์ผ ํ๋ฉฐ[dep1, dep2, dep3]
์ ๊ฐ์ด ์์ฑํด์ผ ํฉ๋๋ค. React๋Object.is
๋น๊ต ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉํ์ฌ ๊ฐ ์์กด์ฑ์ ์ด์ ๊ฐ๊ณผ ๋น๊ตํฉ๋๋ค. ์์กด์ฑ์ ์ ํ ์ง์ ํ์ง ์์ผ๋ฉด ์ปดํฌ๋ํธ๋ฅผ ๋ค์ ๋ ๋๋งํ ๋๋ง๋ค Effect๊ฐ ๋ค์ ์คํ๋ฉ๋๋ค.
๋ฐํ ๊ฐ
useInsertionEffect
๋ undefined
๋ฅผ ๋ฐํํฉ๋๋ค.
์ฃผ์์ฌํญ
- ์ดํํธ๋ ํด๋ผ์ด์ธํธ์์๋ง ์คํ๋ฉ๋๋ค. ์๋ฒ ๋ ๋๋ง ์ค์๋ ์คํ๋์ง ์์ต๋๋ค.
useInsertionEffect
๋ด๋ถ์์๋ ์ํ๋ฅผ ์ ๋ฐ์ดํธํ ์ ์์ต๋๋ค.useInsertionEffect
๊ฐ ์คํ๋๋ ์์ ์ ref๋ ์์ง ์ฐ๊ฒฐ๋์ง ์์๊ณ , DOM๋ ์์ง ์ ๋ฐ์ดํธ ๋์ง ์์์ต๋๋ค.
์ฌ์ฉ๋ฒ
CSS-in-JS ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ๋์ ์คํ์ผ ์ฃผ์ ํ๊ธฐ
์ ํต์ ์ผ๋ก plain CSS๋ฅผ ์ฌ์ฉํด React ์ปดํฌ๋ํธ์ ์คํ์ผ์ ์ง์ ํ์ต๋๋ค.
// JS ํ์ผ ์์์
<button className="success" />
// CSS ํ์ผ ์์์
.success { color: green; }
์ผ๋ถ ํ์ CSS ํ์ผ์ ์์ฑํ๋ ๋์ ์๋ฐ์คํฌ๋ฆฝํธ ์ฝ๋์์ ์ง์ ์คํ์ผ์ ์์ฑํ๋ ๊ฒ์ ์ ํธํฉ๋๋ค. ์ด ๊ฒฝ์ฐ ์ผ๋ฐ์ ์ผ๋ก CSS-in-JS ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋๋ ๋๊ตฌ๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค. CSS-in-JS์๋ ์ธ ๊ฐ์ง ์ผ๋ฐ์ ์ธ ์ ๊ทผ ๋ฐฉ์์ด ์์ต๋๋ค:
- ์ปดํ์ผ๋ฌ๋ฅผ ์ฌ์ฉํ์ฌ CSS ํ์ผ๋ก ์ ์ ์ถ์ถ
- ์ธ๋ผ์ธ ์คํ์ผ, ์:
<div style={{ opacity: 1 }}>
- ๋ฐํ์์
<style>
ํ๊ทธ ์ฃผ์
CSS-in-JS๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ ์ฒ์ ๋ ๊ฐ์ง ์ ๊ทผ ๋ฐฉ์(์ ์ ์คํ์ผ์ ๊ฒฝ์ฐ CSS ํ์ผ, ๋์ ์คํ์ผ์ ๊ฒฝ์ฐ ์ธ๋ผ์ธ ์คํ์ผ)์ ์กฐํฉํ์ฌ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค. ๋ฐํ์ <style>
ํ๊ทธ ์ฃผ์
์ ๋ค์ ๋ ๊ฐ์ง ์ด์ ๋ก ๊ถ์ฅํ์ง ์์ต๋๋ค.
- ๋ฐํ์ ์ฃผ์ ์ ๋ธ๋ผ์ฐ์ ์์ ์คํ์ผ์ ํจ์ฌ ๋ ์์ฃผ ๋ค์ ๊ณ์ฐํ๋๋ก ํฉ๋๋ค.
- ๋ฐํ์ ์ฃผ์ ์ด React ์๋ช ์ฃผ๊ธฐ ์ค์ ์๋ชป๋ ์์ ์ ๋ฐ์ํ๋ฉด ์๋๊ฐ ๋งค์ฐ ๋๋ ค์ง ์ ์์ต๋๋ค.
์ฒซ ๋ฒ์งธ ๋ฌธ์ ๋ ํด๊ฒฐํ ์ ์์ง๋ง useInsertionEffect
๋ฅผ ์ฌ์ฉํ๋ฉด ๋ ๋ฒ์งธ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์ต๋๋ค.
useInsertionEffect
๋ฅผ ํธ์ถํ์ฌ DOM ๋ณ๊ฒฝ ์ ์ ์คํ์ผ์ ์ฃผ์
ํฉ๋๋ค:
// CSS-in-JS ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์์์
let isInserted = new Set();
function useCSS(rule) {
useInsertionEffect(() => {
// ์์ ์ค๋ช
ํ๋ฏ์ด <style> ํ๊ทธ์ ๋ฐํ์ ์ฃผ์
์ ๊ถ์ฅํ์ง ์์ต๋๋ค.
// ํ์ง๋ง ๊ผญ ์ฃผ์
ํด์ผ ํ๋ค๋ฉด useInsertionEffect์์ ์ฃผ์
ํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.
if (!isInserted.has(rule)) {
isInserted.add(rule);
document.head.appendChild(getStyleForRule(rule));
}
});
return rule;
}
function Button() {
const className = useCSS('...');
return <div className={className} />;
}
useEffect
์ ๋ง์ฐฌ๊ฐ์ง๋ก useInsertionEffect
๋ ์๋ฒ์์ ์คํ๋์ง ์์ต๋๋ค. ์๋ฒ์์ ์ด๋ค CSS ๊ท์น์ด ์ฌ์ฉ๋์๋์ง ์์งํด์ผ ํ๋ ๊ฒฝ์ฐ ๋ ๋๋ง ์ค์ ์์งํ ์ ์์ต๋๋ค:
let collectedRulesSet = new Set();
function useCSS(rule) {
if (typeof window === 'undefined') {
collectedRulesSet.add(rule);
}
useInsertionEffect(() => {
// ...
});
return rule;
}
Deep Dive
๋ ๋๋ง ์ค์ ์คํ์ผ์ ์ฃผ์ ํ๊ณ React๊ฐ non-blocking update๋ฅผ ์ฒ๋ฆฌํ๋ ๊ฒฝ์ฐ ๋ธ๋ผ์ฐ์ ๋ ์ปดํฌ๋ํธ ํธ๋ฆฌ๋ฅผ ๋ ๋๋งํ๋ ๋์ ๋งค ํ๋ ์๋ง๋ค ์คํ์ผ์ ๋ค์ ๊ณ์ฐํ๋ฏ๋ก ๋งค์ฐ ๋๋ฆด ์ ์์ต๋๋ค.
useInsertionEffect
๋ ์ปดํฌ๋ํธ์์ ๋ค๋ฅธ Effect๊ฐ ์คํ๋ ๋ <style>
ํ๊ทธ๊ฐ ์ฃผ์
๋์ด ์์์ ๋ณด์ฅํ๊ธฐ ๋๋ฌธ์ useLayoutEffect
๋๋ useEffect
๋ก ์คํ์ผ์ ์ฃผ์
ํ๋ ๊ฒ๋ณด๋ค ๋ซ์ต๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ์ค๋๋ ์คํ์ผ๋ก ์ธํด ์ผ๋ฐ Effects์ ๋ ์ด์์ ๊ณ์ฐ์ด ์๋ชป๋ ์ ์์ต๋๋ค.