따라서 컴포넌트가 렌더링되거나 업데이트될 때마다 서버 연결을 설정하는 effect가 실행되어야 합니다
import { useEffect } from 'react';
function MyComponent() {
useEffect(() => {
// Code here will run after *every* render
});
return <div/>;
}
import { useState, useRef, useEffect } from 'react';
function VideoPlayer({ src, isPlaying }) {
const ref = useRef(null);
if (isPlaying) {
ref.current.play(); // Calling these while rendering isn't allowed.
} else {
ref.current.pause(); // Also, this crashes.
}
return <video ref={ref} src={src} loop playsInline />;
}
export default function App() {
const [isPlaying, setIsPlaying] = useState(false);
return (
<>
<button onClick={() => setIsPlaying(!isPlaying)}>
{isPlaying ? 'Pause' : 'Play'}
</button>
<VideoPlayer
isPlaying={isPlaying}
src="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4"
/>
</>
);
}
ref는 React에서 DOM 요소에 접근하기 위해 사용되는 기능입니다. useRef
훅을 사용하여 ref 변수를 생성하고, ref를 비디오 요소에 연결하기 위해 <video>
요소의 ref prop으로 전달하고 있습니다.
컴포넌트가 렌더링될 때, if문 내부에서 isPlaying
의 상태에 따라 ref.current.play()
또는 ref.current.pause()
가 호출되는데, 이 부분이 문제를 일으키는 원인입니다.
React에서는 컴포넌트의 렌더링 중에 DOM 요소를 조작하는 것을 허용하지 않습니다. 따라서 ref.current.play()
와 ref.current.pause()
를 렌더링 도중에 호출하는 것은 허용되지 않습니다.
이러한 동작을 구현하기 위해 React에서는 useEffect
훅을 사용할 수 있습니다. useEffect
훅은 컴포넌트가 렌더링된 후에 특정 동작을 수행하도록 할 수 있는 기능입니다.
import { useState, useRef, useEffect } from 'react';
function VideoPlayer({ src, isPlaying }) {
const ref = useRef(null);
useEffect(() => {
if (isPlaying) {
ref.current.play();
} else {
ref.current.pause();
}
});
return <video ref={ref} src={src} loop playsInline />;
}
export default function App() {
const [isPlaying, setIsPlaying] = useState(false);
return (
<>
<button onClick={() => setIsPlaying(!isPlaying)}>
{isPlaying ? 'Pause' : 'Play'}
</button>
<VideoPlayer isPlaying={isPlaying}
src="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4"
/>
</>
);
}
<video>
tag is in the DOM with the right props. Then React will run your Effect. Finally, your Effect will call play() or pause() depending on the value of isPlaying.const [count, setCount] = useState(0);
useEffect(() => {
setCount(count + 1);
});
useEffect(() => {
if (isPlaying) {
console.log('Calling video.play()');
ref.current.play();
} else {
console.log('Calling video.pause()');
ref.current.pause();
}
}, []); // This causes an error
useEffect(() => {
if (isPlaying) {
// codes
}, [isPlaying]); // must be declared here
import { useState, useRef, useEffect } from 'react';
function VideoPlayer({ src, isPlaying }) {
const ref = useRef(null);
useEffect(() => {
if (isPlaying) { console.log('Calling video.play()');
ref.current.play();
} else { console.log('Calling video.pause()');
ref.current.pause();
}
}, [isPlaying]);
return <video ref={ref} src={src} loop playsInline />;
}
export default function App() {
const [isPlaying, setIsPlaying] = useState(false);
const [text, setText] = useState('');
return ( <>
<input value={text} onChange={e => setText(e.target.value)} />
<button onClick={() => setIsPlaying(!isPlaying)}>
{isPlaying ? 'Pause' : 'Play'}
</button>
<VideoPlayer isPlaying={isPlaying}
src="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4"
/>
</>
);}
useEffect(() => {
// This runs after every render
});
useEffect(() => {
// This runs only on mount (when the component appears)
}, []);
useEffect(() => {
// This runs on mount *and also* if either a or b have changed since the last render
}, [a, b]);
useEffect(() => {
const connection = createConnection();
connection.connect();
}, []);
[]
(empty). This tells React to only run this code when the component “mounts”, i.e. appears on the screen for the first time.import { useEffect } from 'react';
import { createConnection } from './chat.js';
export default function ChatRoom() {
useEffect(() => {
const connection = createConnection();
connection.connect();
}, []);
return <h1>Welcome to the chat!</h1>;
}
export function createConnection() {
// A real implementation would actually
connect to the server
return {
connect() {
console.log('✅ Connecting...');
},
disconnect() {
console.log('❌ Disconnected.');
}
};
}
return () => { connection.disconnect() };
import { useState, useEffect } from 'react';
import { createConnection } from './chat.js';
export default function ChatRoom() {
useEffect(() => {
const connection = createConnection();
connection.connect();
return () => connection.disconnect();
}, []);
return <h1>Welcome to the chat!</h1>;
}
export function createConnection() {
// A real implementation would actually connect to the server
return {
connect() {
console.log('✅ Connecting...');
},
disconnect() {
console.log('❌ Disconnected.');
}
};
}
useEffect(() => {
let ignore = false;
async function startFetching() {
const json = await fetchTodos(userId);
if (!ignore) {
setTodos(json);
}
}
startFetching();
return () => {
ignore = true;
};
}, [userId]);