따라서 컴포넌트가 렌더링되거나 업데이트될 때마다 서버 연결을 설정하는 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]);