useEffect
useEffect γ―γγ³γ³γγΌγγ³γγε€ι¨γ·γΉγγ γ¨εζγγγγγοΏ½? React γγγ―γ§γγ
useEffect(setup, dependencies?)- γͺγγ‘γ¬γ³γΉ
- δ½Ώη¨ζ³
- ε€ι¨γ·γΉγγ γΈοΏ½?ζ₯ηΆ
- γ«γΉγΏγ γγγ―γ«γ¨γγ§γ―γγγ©γγγγ
- ι React γ¦γ£γΈγ§γγοΏ½?εΆεΎ‘
- γ¨γγ§γ―γγδ½Ώγ£γγγΌγΏγγ§γγ
- γͺγ’γ―γγ£γγͺδΎει εοΏ½?ζοΏ½?οΏ½
- γ¨γγ§γ―γε γ§δ»₯εοΏ½? state γ«εΊγ₯γγ¦ state γζ΄ζ°γγ
- γͺγγΈγ§γ―γεοΏ½?δΈθ¦γͺδΎεε€γει€γγ
- ι’ζ°εοΏ½?δΈθ¦γͺδΎεε€γει€γγ
- γ¨γγ§γ―γγγζζ°οΏ½? props γ¨ state γθͺγΏεγ
- γ΅γΌγγ¨γ―γ©γ€γ’γ³γγ§η°γͺγγ³γ³γγ³γγ葨瀺γγ
- γγ©γγ«γ·γ₯γΌγγ£γ³γ°
- γ³γ³γγΌγγ³γοΏ½?γγ¦γ³γζγ«γ¨γγ§γ―γγ 2 εοΏ½?οΏ½θ‘γγγ
- γ¨γγ§γ―γγεγ¬γ³γγΌγγ¨γ«οΏ½?οΏ½θ‘γγγ
- γ¨γγ§γ―γγη‘ιγ«γΌγγ§εοΏ½?οΏ½θ‘γγηΆγγ
- γ³γ³γγΌγγ³γγγ’γ³γγ¦γ³γγγγ¦γγͺγοΏ½?γ«γ―γͺγΌγ³γ’γγγγΈγγ―γοΏ½?οΏ½θ‘γγγ
- γ¨γγ§γ―γγ葨瀺γ«ι’γγγγ¨γθ‘γ£γ¦γγγοΏ½?οΏ½θ‘εγ«γ‘γγ€γγθ¦γγγ
γͺγγ‘γ¬γ³γΉ
useEffect(setup, dependencies?)
γ³γ³γγΌγγ³γοΏ½?γγγγ¬γγ«γ§ useEffect γεΌγ³εΊγγ¦γγ¨γγ§γ―γ (Effect) γοΏ½?οΏ½θ¨γγΎγγ
import { useEffect } from 'react';
import { createConnection } from './chat.js';
function ChatRoom({ roomId }) {
const [serverUrl, setServerUrl] = useState('https://localhost:1234');
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => {
connection.disconnect();
};
}, [serverUrl, roomId]);
// ...
}εΌζ°
-
setup: γ¨γγ§γ―γοΏ½?γγΈγγ―γθ¨θΏ°γγγι’ζ°γ§γγγοΏ½?γ»γγγ’γγι’ζ°γ―γγͺγγ·γ§γ³γ§γ―γͺγΌγ³γ’γγι’ζ°γθΏγγγ¨γγ§γγΎγγγ³γ³γγΌγγ³γγεγγ¦ DOM γ«θΏ½ε γγγγ¨γReact γ―γ»γγγ’γγι’ζ°γοΏ½?οΏ½θ‘γγΎγγδΎει ε (dependencies) γε€ζ΄γγγεγ¬γ³γγΌζγ«γ―γReact γ―γΎγε€γε€γδ½Ώγ£γ¦γ―γͺγΌγ³γ’γγι’ζ°οΌγγγ°οΌγοΏ½?οΏ½θ‘γγ欑γ«ζ°γγε€γδ½Ώγ£γ¦γ»γγγ’γγι’ζ°γοΏ½?οΏ½θ‘γγΎγγγ³γ³γγΌγγ³γγ DOM γγει€γγγεΎγReact γ―γ―γͺγΌγ³γ’γγι’ζ°γζεΎγ«γγδΈεΊ¦οΏ½?οΏ½θ‘γγΎγγ -
ηη₯ε―θ½
dependencies:setupγ³γΌγε γ§εη §γγγγγΉγ¦οΏ½?γͺγ’γ―γγ£γγͺε€οΏ½?γͺγΉγγ§γγγͺγ’γ―γγ£γγͺε€γ«γ―γpropsγstateγγ³γ³γγΌγγ³γζ¬δ½γ«η΄ζ₯οΏ½?οΏ½θ¨γγγγγΉγ¦οΏ½?ε€ζ°γγγ³ι’ζ°γε«γΎγγΎγγγͺγ³γΏγ React η¨γ«θ¨οΏ½?οΏ½γγγ¦γγε ΄εγγγΉγ¦οΏ½?γͺγ’γ―γγ£γγͺε€γδΎεε€γ¨γγ¦ζ£γγζοΏ½?οΏ½γγγ¦γγγη’Ίθͺγ§γγΎγγδΎεε€οΏ½?γͺγΉγγ―θ¦η΄ ζ°γδΈοΏ½?οΏ½γ§γγεΏ θ¦γγγγ[dep1, dep2, dep3]οΏ½?γγγ«γ€γ³γ©γ€γ³γ§θ¨θΏ°γγεΏ θ¦γγγγΎγγReact γ―γObject.isγδ½Ώγ£γζ―θΌγ§γγγγγοΏ½?δΎεε€γδ»₯εοΏ½?ε€γ¨ζ―θΌγγΎγγγοΏ½?εΌζ°γηη₯γγγ¨γγ¨γγ§γ―γγ―γ³γ³γγΌγγ³γοΏ½?ζ―εοΏ½?γ¬γ³γγΌεΎγ«εοΏ½?οΏ½θ‘γγγΎγγδΎεε€οΏ½?ι εγζΈ‘γε ΄εγ¨η©ΊοΏ½?ι εγζΈ‘γε ΄εγγγγ³δ½γζΈ‘γγͺγε ΄εοΏ½?ιγγη’Ίθͺγγ¦γγ γγγ
θΏγε€
useEffect γ― undefined γθΏγγΎγγ
注ζηΉ
-
useEffectγ―γγγ―γ§γγγγγγ³γ³γγΌγγ³γοΏ½?γγγγ¬γγ«γγ«γΉγΏγ γγγ―ε γ§οΏ½?γΏεΌγ³εΊγγγ¨γγ§γγΎγγγ«γΌγγζ‘δ»ΆζοΏ½?δΈγ§εΌγ³εΊγγγ¨γ―γ§γγΎγγγγγγεΏ θ¦γͺε ΄εγ―γζ°γγγ³γ³γγΌγγ³γγζ½εΊγγγοΏ½?δΈγ« state γη§»εγγγ¦γγ γγγ -
ε€ι¨γ·γΉγγ γ¨εζγγεΏ θ¦γγͺγε ΄εγγ¨γγ§γ―γγ―γγγγδΈθ¦γ§γγ
-
Strict Mode γζεΉγͺε ΄εγReact γ―ζ¬η©οΏ½?γ»γγγ’γγοΏ½?εγ«γιηΊζε°η¨οΏ½?γ»γγγ’γγ+γ―γͺγΌγ³γ’γγγ΅γ€γ―γ«γ 1 εθΏ½ε γ§οΏ½?οΏ½θ‘γγΎγγγγγ―γγ―γͺγΌγ³γ’γγγγΈγγ―γγ»γγγ’γγγγΈγγ―γ¨ι‘οΏ½?γγγ«ε―ΎεΏγγ¦γγγγ»γγγ’γγγ§θ‘γγγγγ¨γεζ’γΎγγ―ε γ«ζ»γγ¦γγγγ¨γδΏθ¨ΌγγγγοΏ½?γΉγγ¬γΉγγΉγγ§γγει‘γηΊηγγε ΄εγ―γγ―γͺγΌγ³γ’γγι’ζ°γοΏ½?οΏ½θ£ γγΎγγ
-
δΎει εοΏ½?δΈι¨γ«γ³γ³γγΌγγ³γε γ§οΏ½?οΏ½ηΎ©γγγγͺγγΈγ§γ―γγι’ζ°γγγε ΄εγγ¨γγ§γ―γγεΏ θ¦δ»₯δΈγ«εοΏ½?οΏ½θ‘γγγε―θ½ζ§γγγγΎγγγγγοΏ½?ζ£γγγ«γ―γγͺγγΈγ§γ―γεγγγ³ι’ζ°εοΏ½?δΈθ¦γͺδΎεε€γει€γγΎγγγΎγγγ¨γγ§γ―γοΏ½?ε€ι¨γ« state οΏ½?ζ΄ζ°γιγͺγ’γ―γγ£γγͺγγΈγγ―γζ½εΊγγγγ¨γγ§γγΎγγ
-
γ¨γγ§γ―γγγ¦γΌγΆζδ½οΌγ―γͺγγ―γͺγ©οΌγ«γγ£γ¦εΌγθ΅·γγγγγοΏ½?γ§γͺγε ΄εγReact γ―ιεΈΈγγγ©γ¦γΆγζ°γγη»ι’γζη»γγεΎγ«γ¨γγ§γ―γγοΏ½?οΏ½θ‘γγΎγγγγͺγοΏ½?γ¨γγ§γ―γγοΌγγΌγ«γγγοΏ½?ι οΏ½?γͺγ©οΌδ½γθ¦θ¦ηγͺδ½ζ₯γθ‘γ£γ¦γγι ε»ΆγοΏ½?η«γ€ε ΄εοΌγ‘γγ€γγͺγ©οΌγ
useEffectγuseLayoutEffectγ«οΏ½?γζγγ¦γγ γγγ -
γ¨γγ§γ―γγγ¦γΌγΆζδ½οΌγ―γͺγγ―γͺγ©οΌγ«γγ£γ¦εΌγθ΅·γγγγε ΄εγ§γγγγ©γ¦γΆγ―γ¨γγ§γ―γε οΏ½? state ζ΄ζ°ε¦ηοΏ½?εγ«η»ι’γεζη»γγε―θ½ζ§γγγγΎγγιεΈΈγγγγζγΎγγεδ½γ§γγγγγγγγ©γ¦γΆγ«γγη»ι’οΏ½?εζη»γγγγγ―γγͺγγγ°γͺγγͺγε ΄εγ
useEffectγuseLayoutEffectγ«οΏ½?γζγγεΏ θ¦γγγγΎγγ -
γ¨γγ§γ―γγ―γ―γ©γ€γ’γ³γδΈγ§οΏ½?γΏοΏ½?οΏ½θ‘γγγΎγγγ΅γΌγγ¬γ³γγͺγ³γ°δΈγ«γ―οΏ½?οΏ½θ‘γγγΎγγγ
δ½Ώη¨ζ³
ε€ι¨γ·γΉγγ γΈοΏ½?ζ₯ηΆ
γ³γ³γγΌγγ³γγ«γγ£γ¦γ―θͺθΊ«γγγΌγΈγ«θ‘¨η€Ίγγγ¦γγιγγγγγ―γΌγ―γδ½γγοΏ½?γγ©γ¦γΆ APIγγΎγγ―γ΅γΌγγγΌγγ£γ©γ€γγ©γͺγ¨οΏ½?ζ₯ηΆγηΆζγγεΏ θ¦γγγγοΏ½?γγγγΎγγγγγοΏ½?γ·γΉγγ γ― React γ«γγ£γ¦εΆεΎ‘γγγ¦γγͺγγγγε€ι¨ (external) οΏ½?γοΏ½?γ§γγ
γ³γ³γγΌγγ³γγε€ι¨γ·γΉγγ γ«ζ₯ηΆγγγ«γ―γγ³γ³γγΌγγ³γοΏ½?γγγγ¬γγ«γ§ useEffect γεΌγ³εΊγγΎγγ
import { useEffect } from 'react';
import { createConnection } from './chat.js';
function ChatRoom({ roomId }) {
const [serverUrl, setServerUrl] = useState('https://localhost:1234');
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => {
connection.disconnect();
};
}, [serverUrl, roomId]);
// ...
}useEffect γ«γ― 2 γ€οΏ½?εΌζ°γζΈ‘γεΏ
θ¦γγγγΎγγ
- γ·γΉγγ γ«ζ₯ηΆγγγ»γγγ’γγγ³γΌγγε«γγ»γγγ’γγι’ζ°γ
- γοΏ½?γ·γΉγγ γγεζγγγ―γͺγΌγ³γ’γγγ³γΌγγε«γγ―γͺγΌγ³γ’γγι’ζ°γθΏγεΏ θ¦γγγγΎγγ
- γγγοΏ½?ι’ζ°ε γ§δ½Ώη¨γγγγ³γ³γγΌγγ³γγγοΏ½?γγΉγ¦οΏ½?ε€γε«γγ δΎεε€οΏ½?γͺγΉγγ
React γ―εΏ θ¦γ«εΏγγ¦γ»γγγ’γγι’ζ°γ¨γ―γͺγΌγ³γ’γγι’ζ°γεΌγ³εΊγγγγγ―θ€ζ°εθ‘γγγγγ¨γγγγΎγγ
- γ³γ³γγΌγγ³γγγγΌγΈγ«θΏ½ε οΌγγ¦γ³γοΌγγγγ¨γγ»γγγ’γγγ³γΌγγοΏ½?οΏ½θ‘γγγΎγγ
- δΎεε€γε€ζ΄γγγδΈγ§γ³γ³γγΌγγ³γγεγ¬γ³γγΌγγγεΊ¦γ«οΌ
- γΎγγε€γ props γ¨ state γ§γ―γͺγΌγ³γ’γγγ³γΌγγοΏ½?οΏ½θ‘γγγΎγγ
- 欑γ«γζ°γγ props γ¨ state γ§γ»γγγ’γγγ³γΌγγοΏ½?οΏ½θ‘γγγΎγγ
- γ³γ³γγΌγγ³γγγγΌγΈγγει€οΌγ’γ³γγ¦γ³γοΌγγγγ¨γζεΎγ«γ―γͺγΌγ³γ’γγγ³γΌγγοΏ½?οΏ½θ‘γγγΎγγ
δΈθ¨οΏ½?δΎγ§γοΏ½?γ·γΌγ±γ³γΉγθͺ¬ζγγΎγγγγ
δΈθ¨οΏ½? ChatRoom γ³γ³γγΌγγ³γγγγΌγΈγ«θΏ½ε γγγγ¨γserverUrl γ¨ roomId οΏ½?εζε€γδ½Ώγ£γ¦γγ£γγγ«γΌγ γ«ζ₯ηΆγγΎγγserverUrl γΎγγ― roomId γεγ¬γ³γγΌοΏ½?η΅ζγ¨γγ¦ε€ζ΄γγγε ΄εοΌδΎγγ°γγ¦γΌγΆγγγγγγγ¦γ³γ§ε₯οΏ½?γγ£γγγ«γΌγ γιΈζγγε ΄εοΌγγγͺγοΏ½?γ¨γγ§γ―γγ―δ»₯εοΏ½?γ«γΌγ γγεζγγ欑�?γ«γΌγ γ«ζ₯ηΆγγΎγγChatRoom γ³γ³γγΌγγ³γγγγΌγΈγγει€γγγγ¨γγγͺγοΏ½?γ¨γγ§γ―γγ―ζεΎοΏ½?εζγθ‘γγΎγγ
γγ°γθ¦γ€γεΊγγγγ«γιηΊδΈγ«γ― React γ―γ»γγγ’γγγ¨γ―γͺγΌγ³γ’γγγγγ»γγγ’γγοΏ½?εγ« 1 εδ½εγ«οΏ½?οΏ½θ‘γγΎγγγγγ―γγ¨γγ§γ―γοΏ½?γγΈγγ―γζ£γγοΏ½?οΏ½θ£ γγγ¦γγγγ¨γη’ΊθͺγγγΉγγ¬γΉγγΉγγ§γγγγγοΏ½?γ«θ¦γγει‘γεΌγθ΅·γγε ΄εγγ―γͺγΌγ³γ’γγι’ζ°γ«δΈι¨οΏ½?γγΈγγ―γζ¬ γγ¦γγΎγγγ―γͺγΌγ³γ’γγι’ζ°γ―γγ»γγγ’γγι’ζ°γθ‘γ£γ¦γγγγ¨γεζ’γͺγγε γ«ζ»γεΏ θ¦γγγγΎγγεΊζ¬γ«γΌγ«γ¨γγ¦γγ¦γΌγΆγ―γ»γγγ’γγγδΈεΊ¦γγεΌγ°γγ¦γγͺγοΌζ¬ηͺη°ε’οΏ½?ε ΄εοΌγγγ»γγγ’γγ β γ―γͺγΌγ³γ’γγ β γ»γγγ’γγοΏ½?γ·γΌγ±γ³γΉοΌιηΊη°ε’οΏ½?ε ΄εοΌγ§εΌγ°γγ¦γγγγεΊε₯γ§γγͺγγγγ«γγεΏ θ¦γγγγΎγγδΈθ¬ηγͺθ§£ζ±Ίζ³γεη §γγ¦γγ γγγ
εγ¨γγ§γ―γγη¬η«γγγγγ»γΉγ¨γγ¦θ¨θΏ°γγγγγ«γγδΈεοΏ½?γ»γγγ’γγοΌγ―γͺγΌγ³γ’γγοΏ½?γ΅γ€γ―γ«γ γγθγγγγγ«γγ¦γγ γγγγ³γ³γγΌγγ³γγηΎε¨γγ¦γ³γγζ΄ζ°γγ’γ³γγ¦γ³γοΏ½?γ©γγθ‘γ£γ¦γγγγθοΏ½?γγΉγγ§γ―γγγΎγγγγ»γγγ’γγγγΈγγ―γζ£γγγ―γͺγΌγ³γ’γγγγΈγγ―γ¨γε―ΎεΏγγγγγγ¨γ§γγ¨γγ§γ―γγ―γ»γγγ’γγγ¨γ―γͺγΌγ³γ’γγγεΏ θ¦γ«εΏγγ¦δ½εΊ¦οΏ½?οΏ½θ‘γγ¦γει‘γθ΅·γγͺγγε η’γͺγοΏ½?γ¨γͺγγΎγγ
δΎ 1/5: γγ£γγγ΅γΌγγΈοΏ½?ζ₯ηΆ
γοΏ½?δΎγ§γ―γChatRoom γ³γ³γγΌγγ³γγγ¨γγ§γ―γγδ½Ώγ£γ¦ chat.js γ§οΏ½?οΏ½ηΎ©γγγε€ι¨γ·γΉγγ γ«ζ₯ηΆγγ¦γγΎγγβOpen chatβ γζΌγγ¨ ChatRoom γ³γ³γγΌγγ³γγ葨瀺γγγΎγγγοΏ½?γ΅γ³γγγγ―γΉγ―ιηΊγ’γΌγγ§οΏ½?οΏ½θ‘γγγ¦γγγγγγγ‘γγ§θͺ¬ζγγγ¦γγγγγ«γζ₯ηΆγ¨εζοΏ½?γ΅γ€γ―γ«γ 1 εθΏ½ε γ§ηΊηγγΎγγroomId γ¨ serverUrl γγγγγγγ¦γ³γ¨ε
₯εζ¬γ§ε€ζ΄γγ¦γγ¨γγ§γ―γγγγ£γγγ«εζ₯ηΆγγζ§εγη’Ίθͺγγ¦γΏγ¦γγ γγγβClose chatβ γζΌγγ¨γγ¨γγ§γ―γγζεΎοΏ½? 1 εοΏ½?εζδ½ζ₯γθ‘γγΎγγ
import { useState, useEffect } from 'react'; import { createConnection } from './chat.js'; function ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => { connection.disconnect(); }; }, [roomId, serverUrl]); return ( <> <label> Server URL:{' '} <input value={serverUrl} onChange={e => setServerUrl(e.target.value)} /> </label> <h1>Welcome to the {roomId} room!</h1> </> ); } export default function App() { const [roomId, setRoomId] = useState('general'); const [show, setShow] = useState(false); return ( <> <label> Choose the chat room:{' '} <select value={roomId} onChange={e => setRoomId(e.target.value)} > <option value="general">general</option> <option value="travel">travel</option> <option value="music">music</option> </select> </label> <button onClick={() => setShow(!show)}> {show ? 'Close chat' : 'Open chat'} </button> {show && <hr />} {show && <ChatRoom roomId={roomId} />} </> ); }
γ«γΉγΏγ γγγ―γ«γ¨γγ§γ―γγγ©γγγγ
γ¨γγ§γ―γγ―γιΏι£γγγγγ§γγReact οΏ½?ε€γ«εΊγεΏ θ¦γγγγγγ€ηΉοΏ½?οΏ½οΏ½?γ¦γΌγΉγ±γΌγΉγ«ε―Ύγγ¦γγθ―γη΅γΏθΎΌγΏοΏ½?γ½γͺγ₯γΌγ·γ§γ³γγͺγε ΄εγ«δ½Ώη¨γγΎγγγ¨γγ§γ―γγζγ§δ½εΊ¦γζΈγεΏ θ¦γγγγγ¨γ«ζ°δ»γγγγιεΈΈγγγ―γγγͺγοΏ½?γ³γ³γγΌγγ³γγδΎεγγε ±ιοΏ½?ζ―γθγοΏ½?γγοΏ½?γ«γΉγΏγ γγγ―γζ½εΊγγεΏ θ¦γγγγ¨γγγ΅γ€γ³γ§γγ
δΎγγ°γγοΏ½? useChatRoom γ«γΉγΏγ γγγ―γ―γγ¨γγ§γ―γοΏ½?γγΈγγ―γγγοΏ½?οΏ½θ¨ηγͺ API οΏ½?θεΎγ«γι θ½γγγΎγγ
function useChatRoom({ serverUrl, roomId }) {
useEffect(() => {
const options = {
serverUrl: serverUrl,
roomId: roomId
};
const connection = createConnection(options);
connection.connect();
return () => connection.disconnect();
}, [roomId, serverUrl]);
}γοΏ½?εΎγ§γδ»»ζοΏ½?γ³γ³γγΌγγ³γγγδ»₯δΈοΏ½?γγγ«δ½Ώγγγ¨γγ§γγΎγγ
function ChatRoom({ roomId }) {
const [serverUrl, setServerUrl] = useState('https://localhost:1234');
useChatRoom({
roomId: roomId,
serverUrl: serverUrl
});
// ...γ»γγ«γ React οΏ½?γ¨γ³γ·γΉγγ γ«γ―γγγΎγγΎγͺοΏ½?ηοΏ½?γγοΏ½?εͺγγγ«γΉγΏγ γγγ―γε€ζ°ε ¬ιγγγ¦γγΎγγ
γ«γΉγΏγ γγγ―γ§γ¨γγ§γ―γγγ©γγγγζΉζ³γ«γ€γγ¦γγ£γ¨ε¦γΆ
δΎ 1/3: γ«γΉγΏγ useChatRoom γγγ―
γοΏ½?δΎγ―γγγγΎγ§οΏ½?δΎ οΏ½?γγγγγ¨εγγ§γγγγ«γΉγΏγ γγγ―γ«γγΈγγ―γζ½εΊγγγ¦γγΎγγ
import { useState } from 'react'; import { useChatRoom } from './useChatRoom.js'; function ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); useChatRoom({ roomId: roomId, serverUrl: serverUrl }); return ( <> <label> Server URL:{' '} <input value={serverUrl} onChange={e => setServerUrl(e.target.value)} /> </label> <h1>Welcome to the {roomId} room!</h1> </> ); } export default function App() { const [roomId, setRoomId] = useState('general'); const [show, setShow] = useState(false); return ( <> <label> Choose the chat room:{' '} <select value={roomId} onChange={e => setRoomId(e.target.value)} > <option value="general">general</option> <option value="travel">travel</option> <option value="music">music</option> </select> </label> <button onClick={() => setShow(!show)}> {show ? 'Close chat' : 'Open chat'} </button> {show && <hr />} {show && <ChatRoom roomId={roomId} />} </> ); }
ι React γ¦γ£γΈγ§γγοΏ½?εΆεΎ‘
ε€ι¨γ·γΉγγ γγγͺγοΏ½?γ³γ³γγΌγγ³γοΏ½? props γ state γ«εζγγγγγγ¨γγγγΎγγ
δΎγγ°γReact γδ½Ώγ£γ¦γγͺγγ΅γΌγγγΌγγ£θ£½οΏ½?γγγγ¦γ£γΈγ§γγγγγγͺγγ¬γΌγ€γ³γ³γγΌγγ³γγγγε ΄εγγ¨γγ§γ―γγδ½Ώγ£γ¦γγ‘γοΏ½?γ‘γ½γγγεΌγ³εΊγγγγ‘γοΏ½?ηΆζ
γ React γ³γ³γγΌγγ³γοΏ½?ηΎε¨ state γ«εγγγγγ¨γγ§γγΎγγδ»₯δΈγ§γ―γmap-widget.js γ«οΏ½?οΏ½ηΎ©γγγ MapWidget γ―γ©γΉοΏ½?γ€γ³γΉγΏγ³γΉγγ¨γγ§γ―γγδ½ζγγΎγγMap γ³γ³γγΌγγ³γοΏ½? props γ§γγ zoomLevel γε€ζ΄γγγγ¨γγ¨γγ§γ―γγγ―γ©γΉγ€γ³γΉγΏγ³γΉοΏ½? setZoom() γεΌγ³εΊγγ¦γεζγδΏγ‘γΎγγ
import { useRef, useEffect } from 'react'; import { MapWidget } from './map-widget.js'; export default function Map({ zoomLevel }) { const containerRef = useRef(null); const mapRef = useRef(null); useEffect(() => { if (mapRef.current === null) { mapRef.current = new MapWidget(containerRef.current); } const map = mapRef.current; map.setZoom(zoomLevel); }, [zoomLevel]); return ( <div style={{ width: 200, height: 200 }} ref={containerRef} /> ); }
γοΏ½?δΎγ§γ―γγ―γͺγΌγ³γ’γγι’ζ°γ―εΏ
θ¦γγγΎγγγγͺγγͺγγMapWidget γ―γ©γΉγ―θͺθΊ«γ«ζΈ‘γγγ DOM γγΌγοΏ½?γΏγοΏ½?οΏ½ηγγ¦γγγγγ§γγReact οΏ½? Map γ³γ³γγΌγγ³γγγγͺγΌγγει€γγγεΎγDOM γγΌγγ¨ MapWidget γ―γ©γΉγ€γ³γΉγΏγ³γΉγ―γγγ©γ¦γΆοΏ½? JavaScript γ¨γ³γΈγ³γ«γγ£γ¦θͺεηγ«γ¬γγΌγΈγ³γ¬γ―γ·γ§γ³γγγΎγγ
γ¨γγ§γ―γγδ½Ώγ£γγγΌγΏγγ§γγ
γ¨γγ§γ―γγδ½Ώγ£γ¦γγ³γ³γγΌγγ³γγ«εΏ θ¦γͺγγΌγΏγγγ§γγοΌfetch, εεΎοΌγγγγ¨γγ§γγΎγγγγ γγγ¬γΌγ γ―γΌγ―γδ½Ώη¨γγ¦γγε ΄εγ―γγ¨γγ§γ―γγθͺεγ§θ¨θΏ°γγγγγγγγ¬γΌγ γ―γΌγ―οΏ½?γγΌγΏγγ§γγγ‘γ«γγΊγ γδ½Ώη¨γγζΉγγ―γγγ«εΉηηγ§γγγγ¨γ«ζ³¨ζγγ¦γγ γγγ
γ¨γγ§γ―γγδ½Ώγ£γ¦θͺεγ§γγΌγΏγγγ§γγγγγε ΄εγ―γδ»₯δΈοΏ½?γγγͺγ³γΌγγζΈγγγ¨γ«γͺγγΎγγ
import { useState, useEffect } from 'react';
import { fetchBio } from './api.js';
export default function Page() {
const [person, setPerson] = useState('Alice');
const [bio, setBio] = useState(null);
useEffect(() => {
let ignore = false;
setBio(null);
fetchBio(person).then(result => {
if (!ignore) {
setBio(result);
}
});
return () => {
ignore = true;
};
}, [person]);
// ...ignore ε€ζ°γ«ζ³¨οΏ½?γγ¦γγ γγγγγγ― false γ§εζεγγγγ―γͺγΌγ³γ’γγζγ« true γ«θ¨οΏ½?οΏ½γγγΎγγγγγ«γγγγ³γΌγγ βη«ΆεηΆζ
(race condition)β γ«ζ©γΎγγγͺγγγγ«γͺγγΎγγγγγγ―γΌγ―γ¬γΉγγ³γΉγ―γιδΏ‘γγι εΊγ¨η°γͺγι εΊγ§ε±γγγ¨γγγγγ¨γ«ζ³¨ζγγΎγγγγ
import { useState, useEffect } from 'react'; import { fetchBio } from './api.js'; export default function Page() { const [person, setPerson] = useState('Alice'); const [bio, setBio] = useState(null); useEffect(() => { let ignore = false; setBio(null); fetchBio(person).then(result => { if (!ignore) { setBio(result); } }); return () => { ignore = true; } }, [person]); return ( <> <select value={person} onChange={e => { setPerson(e.target.value); }}> <option value="Alice">Alice</option> <option value="Bob">Bob</option> <option value="Taylor">Taylor</option> </select> <hr /> <p><i>{bio ?? 'Loading...'}</i></p> </> ); }
γΎγγasync / await ζ§ζγδ½Ώγ£γ¦ζΈγη΄γγγ¨γγ§γγΎγγγγοΏ½?ε ΄εγ§γγ―γͺγΌγ³γ’γγι’ζ°γζΈ‘γεΏ
θ¦γγγγΎγγ
import { useState, useEffect } from 'react'; import { fetchBio } from './api.js'; export default function Page() { const [person, setPerson] = useState('Alice'); const [bio, setBio] = useState(null); useEffect(() => { async function startFetching() { setBio(null); const result = await fetchBio(person); if (!ignore) { setBio(result); } } let ignore = false; startFetching(); return () => { ignore = true; } }, [person]); return ( <> <select value={person} onChange={e => { setPerson(e.target.value); }}> <option value="Alice">Alice</option> <option value="Bob">Bob</option> <option value="Taylor">Taylor</option> </select> <hr /> <p><i>{bio ?? 'Loading...'}</i></p> </> ); }
γ¨γγ§γ―γε γ§η΄ζ₯γγΌγΏγγ§γγγζΈγγ¨γ³γΌγοΏ½?ηΉ°γθΏγγε’γγγγ£γγ·γ₯γγ΅γΌγγ¬γ³γγͺγ³γ°γ¨γγ£γζι©εγεΎγγθΏ½ε γγγγ¨γι£γγγͺγγΎγγη¬θͺοΏ½?γγγγγ―γ³γγ₯γγγ£γγ‘γ³γγγ³γΉγγ¦γγγ«γΉγΏγ γγγ―γδ½ΏγζΉγη°‘εγ§γγ
γγγ«ζ·±γη₯γ
ηΉγ«οΏ½?οΏ½ε
¨γ«γ―γ©γ€γ’γ³γγ΅γ€γοΏ½?γ’γγͺγ«γγγ¦γ―γγ¨γγ§γ―γοΏ½?δΈγ§ fetch γ³γΌγ«γζΈγγγ¨γ―γγΌγΏγγ§γγοΏ½?δΈθ¬ηγͺζΉζ³γ§γγγγγγγγγ―ιεΈΈγ«ζδ½ζ₯ι ΌγοΏ½?γ’γγγΌγγ§γγγε€§γγͺζ¬ ηΉγγγγΎγγ
- γ¨γγ§γ―γγ―γ΅γΌγδΈγ§γ―εδ½γγΎγγγγγγ―γγ΅γΌγγ¬γ³γγͺγ³γ°γγγεζ HTML γ«γ―γγΌγΏοΏ½?γͺγγγΌγγ£γ³γ°δΈγ¨γγ葨瀺�?γΏγε«γΎγγ¦γγΎγγγ¨γζε³γγΎγγγ―γ©γ€γ’γ³γοΏ½?γ³γ³γγ₯γΌγΏγ―γγγΉγ¦οΏ½? JavaScript γγγ¦γ³γγΌγγγγ’γγͺγγ¬γ³γγΌγγεΎγ«γͺγ£γ¦γγ£γ¨γδ»εΊ¦γ―γγΌγΏγθͺγΏθΎΌγεΏ θ¦γγγγ¨γγγγ¨γ«ζ°δ»γγγ¨γ«γͺγγΎγγγγγ―γγΎγεΉηηγ§γ―γγγΎγγγ
- γ¨γγ§γ―γγ§η΄ζ₯γγΌγΏγγ§γγγθ‘γγ¨γγγγγγ―γΌγ―οΏ½?γ¦γ©γΌγΏγΌγγ©γΌγ«οΌζ»οΌγγδ½ζγγγγγͺγγΎγγθ¦ͺγ³γ³γγΌγγ³γγγ¬γ³γγΌγγγγγδ½γγγΌγΏγγγ§γγγγγγγ«γγ£γ¦εγ³γ³γγΌγγ³γγγ¬γ³γγΌγγδ»εΊ¦γ―γγγδ½γγγΌγΏοΏ½?γγ§γγγιε§γγγγ¨γγ£γε ·εγ§γγγγγγ―γΌγ―γγγΎγιγγͺγε ΄εγγγγ―γγΉγ¦οΏ½?γγΌγΏγδΈ¦θ‘γ§εεΎγγγγγγγͺγι γγͺγγΎγγ
- γ¨γγ§γ―γε γ§η΄ζ₯γγΌγΏγγ§γγγγγ¨γγγγ¨γ―γγγγγγΌγΏγγγͺγγΌγγγγ£γγ·γ₯γγγ¦γγͺγγ¨γγγγ¨γ§γγδΎγγ°γγ³γ³γγΌγγ³γγγ’γ³γγ¦γ³γγγγεΎγ«εγ³γγ¦γ³γγγγε ΄εγγγΌγΏγεεΊ¦εεΎγγεΏ θ¦γγγγΎγγ
- δΊΊγ«γ¨γ£γ¦ζΈγγγγγ³γΌγγ«γͺγγΎγγγη«ΆεηΆζ
οΏ½?γγγͺγγ°γθ΅·γγγͺγγγγ«
fetchγ³γΌγ«γζΈγγγ¨γγγ¨γγγͺγοΏ½?γγ€γ©γΌγγ¬γΌγγ³γΌγγεΏ θ¦γ§γγ
δΈθ¨οΏ½?ζ¬ ηΉγ―γγγ¦γ³γζγ«γγΌγΏγγγ§γγγγοΏ½?γ§γγγ°γReact γ«ιγγγ©οΏ½?γ©γ€γγ©γͺγδ½Ώγε ΄εγ§γε½γ¦γ―γΎγε οΏ½?οΏ½γ§γγγ«γΌγγ£γ³γ°γ¨εζ§γγγΌγΏγγ§γγοΏ½?οΏ½?οΏ½θ£ γδΈζγ«γγγγ¨γγγ¨δΈηηΈγ§γ―γγγΎγγγη§γγ‘γ―δ»₯δΈοΏ½?γ’γγγΌγγγε§γγγΎγγ
- γγ¬γΌγ γ―γΌγ―γδ½Ώη¨γγ¦γγε ΄εγη΅γΏθΎΌγΏοΏ½?γγΌγΏγγ§γγζ©ζ§γδ½Ώη¨γγ¦γγ γγγγ’γγ³γͺ React γγ¬γΌγ γ―γΌγ―γ«γ―γεΉηηγ§δΈθ¨οΏ½?ζ¬ ηΉγγͺγγγΌγΏγγ§γγζ©ζ§γη΅±εγγγ¦γγΎγγ
- γγδ»₯ε€οΏ½?ε ΄εγ―γγ―γ©γ€γ’γ³γγ΅γ€γγγ£γγ·γ₯οΏ½?δ½Ώη¨γζ§η―γζ€θ¨γγ¦γγ γγγδΈθ¬ηγͺγͺγΌγγ³γ½γΌγΉοΏ½?γ½γͺγ₯γΌγ·γ§γ³γ«γ―γReact QueryγuseSWRγγγγ³ React Router 6.4+ γε«γΎγγΎγγθͺεγ§γ½γͺγ₯γΌγ·γ§γ³γζ§η―γγγγ¨γγ§γγΎγγγοΏ½?ε ΄εγγ¨γγ§γ―γγε ι¨γ§δ½Ώη¨γγ€γ€γγͺγ―γ¨γΉγοΏ½?ιθ€ζι€γγ¬γΉγγ³γΉοΏ½?γγ£γγ·γ₯γγγγγ―γΌγ―οΏ½?γ¦γ©γΌγΏγΌγγ©γΌγ«γειΏγγγγοΏ½?γγΈγγ―οΌγγΌγΏοΏ½?γγͺγγΌγγγ«γΌγγ£γ³γ°ι¨γΈοΏ½?γγΌγΏθ¦ζ±οΏ½?ε·»γδΈγοΌγθΏ½ε γγγγ¨γ«γͺγγΎγγ
γγγοΏ½?γ’γγγΌγγγ©γ‘γγι©εγγͺγε ΄εγ―γεΌγηΆγγ¨γγ§γ―γε γ§η΄ζ₯γγΌγΏγγγ§γγγγγγ¨γγ§γγΎγγ
γͺγ’γ―γγ£γγͺδΎει εοΏ½?ζοΏ½?οΏ½
γ¨γγ§γ―γοΏ½?δΎει εγ―γθͺεγ§γιΈγΆγγγγοΏ½?η©γ§γ―γͺγγγ¨γ«ζ³¨ζγγ¦γγ γγγγ¨γγ§γ―γοΏ½?γ³γΌγγ«γγ£γ¦δ½Ώη¨γγγγγΉγ¦οΏ½?γͺγ’γ―γγ£γγͺε€γ―γδΎεε€γ¨γγ¦οΏ½?οΏ½θ¨γγγͺγγγ°γͺγγΎγγγγ¨γγ§γ―γοΏ½?δΎεε€οΏ½?γͺγΉγγ―γε¨ε²οΏ½?γ³γΌγγ«γγ£γ¦ζ±ΊοΏ½?οΏ½γγγΎγγ
function ChatRoom({ roomId }) { // This is a reactive value
const [serverUrl, setServerUrl] = useState('https://localhost:1234'); // This is a reactive value too
useEffect(() => {
const connection = createConnection(serverUrl, roomId); // This Effect reads these reactive values
connection.connect();
return () => connection.disconnect();
}, [serverUrl, roomId]); // β
So you must specify them as dependencies of your Effect
// ...
}serverUrl γΎγγ― roomId γε€ζ΄γγγγ¨γγ¨γγ§γ―γγ―ζ°γγε€γδ½Ώη¨γγ¦γγ£γγγ«εζ₯ηΆγγΎγγ
γͺγ’γ―γγ£γγͺε€γ«γ―γprops γ¨γγ³γ³γγΌγγ³γε
γ«η΄ζ₯οΏ½?οΏ½θ¨γγγγγΉγ¦οΏ½?ε€ζ°γγγ³ι’ζ°γε«γΎγγΎγγroomId γ¨ serverUrl γ―γͺγ’γ―γγ£γγͺε€γ§γγγγγδΎεε€οΏ½?γͺγΉγγγει€γγγγ¨γ―γ§γγΎγγγγγγγηη₯γγγγ¨γγε ΄εγReact η¨οΏ½?γͺγ³γΏγζ£γγθ¨οΏ½?οΏ½γγγ¦γγγ°γγͺγ³γΏγ―γγγοΏ½?ζ£γεΏ
θ¦γͺθͺ€γγ§γγγ¨ζζγγΎγγ
function ChatRoom({ roomId }) {
const [serverUrl, setServerUrl] = useState('https://localhost:1234');
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => connection.disconnect();
}, []); // π΄ React Hook useEffect has missing dependencies: 'roomId' and 'serverUrl'
// ...
}δΎει
εγγδ½γγει€γγγ«γ―γγͺγ³γΏγ«ε―ΎγγγγγδΎεε€γ§γγηη±γγͺγγγ¨γγθ¨ΌζγγγεΏ
θ¦γγγγΎγγδΎγγ°γserverUrl γγ³γ³γγΌγγ³γοΏ½?ε€γ«η§»εγγγ°γγγγγͺγ’γ―γγ£γγͺε€γ§γ―γͺγγεγ¬γ³γγΌζγ«ε€ζ΄γγγͺγγοΏ½?γ§γγγγ¨γθ¨Όζγ§γγΎγγ
const serverUrl = 'https://localhost:1234'; // Not a reactive value anymore
function ChatRoom({ roomId }) {
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => connection.disconnect();
}, [roomId]); // β
All dependencies declared
// ...
}γγγ§ serverUrl γγͺγ’γ―γγ£γγͺε€γ§γͺγγͺγ£γοΌεγ¬γ³γγΌζγ«ε€ζ΄γγγͺγοΌγγγδΎει
εγ«ε
₯γγεΏ
θ¦γγͺγγͺγγΎγγγγ¨γγ§γ―γοΏ½?γ³γΌγγγͺγ’γ―γγ£γγͺε€γδ½Ώη¨γγ¦γγͺγε ΄εγγοΏ½?δΎει
εγ―η©Ί ([]) γ§γγγΉγγ§γγ
const serverUrl = 'https://localhost:1234'; // Not a reactive value anymore
const roomId = 'music'; // Not a reactive value anymore
function ChatRoom() {
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => connection.disconnect();
}, []); // β
All dependencies declared
// ...
}η©ΊοΏ½?δΎει εγ§οΏ½?οΏ½ηΎ©γγγ¨γγ§γ―γγ―γγ³γ³γγΌγγ³γοΏ½? props γ state γε€ζ΄γγγε ΄εγ§γεοΏ½?οΏ½θ‘γγγΎγγγ
δΎ 1/3: δΎει
εγζΈ‘γ
δΎει εγζοΏ½?οΏ½γγγ¨γγ¨γγ§γ―γγ―ζεοΏ½?γ¬γ³γγΌεΎγγγ³δΎει εγε€γγ£γεΎοΏ½?εγ¬γ³γγΌεΎγ«οΏ½?οΏ½θ‘γγγΎγγ
useEffect(() => {
// ...
}, [a, b]); // Runs again if a or b are differentδ»₯δΈοΏ½?δΎγ§γ―γserverUrl γ¨ roomId γ― γͺγ’γ―γγ£γγͺε€γ§γγγγγδΈ‘ζΉγ¨γδΎει
εοΏ½?δΈγ§ζοΏ½?οΏ½γγεΏ
θ¦γγγγΎγγγοΏ½?η΅ζγγγγγγγ¦γ³γ§ε₯οΏ½?γ«γΌγ γιΈζγγγγγ΅γΌγ URL οΏ½?ε
₯εζ¬γη·¨ιγγγγγγ¨γγγ£γγγεζ₯ηΆγγγΎγγγγ γγmessage γ―γ¨γγ§γ―γγ§δ½Ώη¨γγγ¦γγͺγοΌδΎεγγε€γ§γ―γͺγοΌγγγγ‘γγ»γΌγΈγη·¨ιγγ¦γγγ£γγγεζ₯ηΆγγγγγ¨γ―γγγΎγγγ
import { useState, useEffect } from 'react'; import { createConnection } from './chat.js'; function ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); const [message, setMessage] = useState(''); useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => { connection.disconnect(); }; }, [serverUrl, roomId]); return ( <> <label> Server URL:{' '} <input value={serverUrl} onChange={e => setServerUrl(e.target.value)} /> </label> <h1>Welcome to the {roomId} room!</h1> <label> Your message:{' '} <input value={message} onChange={e => setMessage(e.target.value)} /> </label> </> ); } export default function App() { const [show, setShow] = useState(false); const [roomId, setRoomId] = useState('general'); return ( <> <label> Choose the chat room:{' '} <select value={roomId} onChange={e => setRoomId(e.target.value)} > <option value="general">general</option> <option value="travel">travel</option> <option value="music">music</option> </select> <button onClick={() => setShow(!show)}> {show ? 'Close chat' : 'Open chat'} </button> </label> {show && <hr />} {show && <ChatRoom roomId={roomId}/>} </> ); }
γ¨γγ§γ―γε γ§δ»₯εοΏ½? state γ«εΊγ₯γγ¦ state γζ΄ζ°γγ
γ¨γγ§γ―γγγδ»₯εοΏ½? state γ«εΊγ₯γγ¦ state γζ΄ζ°γγγε ΄εγει‘γηΊηγγγγγγγΎγγγ
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
const intervalId = setInterval(() => {
setCount(count + 1); // You want to increment the counter every second...
}, 1000)
return () => clearInterval(intervalId);
}, [count]); // π© ... but specifying `count` as a dependency always resets the interval.
// ...
}count γ―γͺγ’γ―γγ£γγͺε€γͺοΏ½?γ§γδΎει
εγ«ζοΏ½?οΏ½γγεΏ
θ¦γγγγΎγγγγ γγγοΏ½?γΎγΎγ§γ― count γε€ζ΄γγγγγ³γ«γγ¨γγ§γ―γγγ―γͺγΌγ³γ’γγγ¨γ»γγγ’γγγηΉ°γθΏγγγ¨γ«γͺγγΎγγγγγ―ζγΎγγγγγΎγγγ
γοΏ½?ει‘γθ§£ζ±Ίγγγ«γ―γsetCount γ« c => c + 1 γ¨γγ state ζ΄ζ°η¨ι’ζ°γζΈ‘γγΎγγ
import { useState, useEffect } from 'react'; export default function Counter() { const [count, setCount] = useState(0); useEffect(() => { const intervalId = setInterval(() => { setCount(c => c + 1); // β Pass a state updater }, 1000); return () => clearInterval(intervalId); }, []); // β Now count is not a dependency return <h1>{count}</h1>; }
c => c + 1 γ count + 1 οΏ½?代γγγ«ζΈ‘γγγγ«γͺγ£γοΏ½?γ§γγοΏ½?γ¨γγ§γ―γγ―γγ count γ«δΎεγγεΏ
θ¦γ―γγγΎγγγγοΏ½?οΏ½?ζ£οΏ½?η΅ζγcount γε€εγγγγ³γ«γ€γ³γΏγΌγγ«οΏ½?γ―γͺγΌγ³γ’γγγ¨γ»γγγ’γγγθ‘γγͺγγ¦γγγγͺγγΎγγ
γͺγγΈγ§γ―γεοΏ½?δΈθ¦γͺδΎεε€γει€γγ
γ¨γγ§γ―γγγ¬γ³γγΌδΈγ«δ½ζγγγγͺγγΈγ§γ―γγι’ζ°γ«δΎεγγ¦γγε ΄εγεΏ
θ¦δ»₯δΈγ«γ¨γγ§γ―γγοΏ½?οΏ½θ‘γγγ¦γγΎγγγ¨γγγγΎγγγγ¨γγ°γγοΏ½?γ¨γγ§γ―γγ― options γͺγγΈγ§γ―γγγ¬γ³γγΌγγ¨γ«η°γͺγγγγζ―εοΏ½?γ¬γ³γγΌεΎγ«εζ₯ηΆγθ‘γ£γ¦γγΎγγΎγοΌ
const serverUrl = 'https://localhost:1234';
function ChatRoom({ roomId }) {
const [message, setMessage] = useState('');
const options = { // π© This object is created from scratch on every re-render
serverUrl: serverUrl,
roomId: roomId
};
useEffect(() => {
const connection = createConnection(options); // It's used inside the Effect
connection.connect();
return () => connection.disconnect();
}, [options]); // π© As a result, these dependencies are always different on a re-render
// ...γ¬γ³γγΌδΈγ«ζ°γγ«δ½ζγγγγͺγγΈγ§γ―γγδΎεε€γ¨γγ¦δ½Ώη¨γγͺγγ§γγ γγγ代γγγ«γγ¨γγ§γ―γοΏ½?δΈγ§γͺγγΈγ§γ―γγδ½ζγγΎγοΌ
import { useState, useEffect } from 'react'; import { createConnection } from './chat.js'; const serverUrl = 'https://localhost:1234'; function ChatRoom({ roomId }) { const [message, setMessage] = useState(''); useEffect(() => { const options = { serverUrl: serverUrl, roomId: roomId }; const connection = createConnection(options); connection.connect(); return () => connection.disconnect(); }, [roomId]); return ( <> <h1>Welcome to the {roomId} room!</h1> <input value={message} onChange={e => setMessage(e.target.value)} /> </> ); } export default function App() { const [roomId, setRoomId] = useState('general'); return ( <> <label> Choose the chat room:{' '} <select value={roomId} onChange={e => setRoomId(e.target.value)} > <option value="general">general</option> <option value="travel">travel</option> <option value="music">music</option> </select> </label> <hr /> <ChatRoom roomId={roomId} /> </> ); }
γ¨γγ§γ―γοΏ½?δΈγ§ options γͺγγΈγ§γ―γγδ½ζγγγγγ«γͺγ£γοΏ½?γ§γγ¨γγ§γ―γθͺδ½γ― roomId ζεεγ«γγδΎεγγΎγγγ
γοΏ½?οΏ½?ζ£γ«γγγε
₯εγγ£γΌγ«γγ«ζεγε
₯εγγ¦γγγ£γγγεζ₯ηΆγγγγγ¨γ―γͺγγͺγγΎγγγͺγγΈγ§γ―γγ―εγ¬γ³γγΌοΏ½?γγ³γ«εδ½ζγγγοΏ½?γ¨γ―η°γͺγγroomId οΏ½?γγγͺζεεγ―ε₯οΏ½?ε€γ«θ¨οΏ½?οΏ½γγͺγιγε€ζ΄γγγΎγγγδΎεε€οΏ½?ει€γ«ι’γγθ©³η΄°γθͺγγ
ι’ζ°εοΏ½?δΈθ¦γͺδΎεε€γει€γγ
γ¨γγ§γ―γγγ¬γ³γγΌδΈγ«δ½ζγγγγͺγγΈγ§γ―γγι’ζ°γ«δΎεγγ¦γγε ΄εγεΏ
θ¦δ»₯δΈγ«γ¨γγ§γ―γγοΏ½?οΏ½θ‘γγγ¦γγΎγγγ¨γγγγΎγγγγ¨γγ°γγοΏ½?γ¨γγ§γ―γγ― createOptions ι’ζ°γγ¬γ³γγΌγγ¨γ«η°γͺγγγγζ―εεζ₯ηΆγθ‘γ£γ¦γγΎγγΎγοΌ
function ChatRoom({ roomId }) {
const [message, setMessage] = useState('');
function createOptions() { // π© This function is created from scratch on every re-render
return {
serverUrl: serverUrl,
roomId: roomId
};
}
useEffect(() => {
const options = createOptions(); // It's used inside the Effect
const connection = createConnection();
connection.connect();
return () => connection.disconnect();
}, [createOptions]); // π© As a result, these dependencies are always different on a re-render
// ...εγ¬γ³γγΌοΏ½?γγ³γ«ζ°γγι’ζ°γδ½ζγγγγ¨γγγθͺδ½γ«γ―ει‘γ―γͺγγζι©εγγγγ¨γγεΏ θ¦γ―γγγΎγγγγγ γγγ¨γγ§γ―γοΏ½?δΎεε€γ¨γγ¦γγγδ½Ώη¨γγε ΄εγζ―εοΏ½?γ¬γ³γγΌεΎγ«γ¨γγ§γ―γγεοΏ½?οΏ½θ‘γγγ¦γγΎγγγ¨γ«γͺγγΎγγ
γ¬γ³γγΌδΈγ«δ½ζγγγι’ζ°γδΎεε€γ¨γγ¦δ½Ώη¨γγγγ¨γ―ιΏγγ¦γγ γγγ代γγγ«γγ¨γγ§γ―γοΏ½?ε ι¨γ§οΏ½?οΏ½θ¨γγγγγ«γγΎγγ
import { useState, useEffect } from 'react'; import { createConnection } from './chat.js'; const serverUrl = 'https://localhost:1234'; function ChatRoom({ roomId }) { const [message, setMessage] = useState(''); useEffect(() => { function createOptions() { return { serverUrl: serverUrl, roomId: roomId }; } const options = createOptions(); const connection = createConnection(options); connection.connect(); return () => connection.disconnect(); }, [roomId]); return ( <> <h1>Welcome to the {roomId} room!</h1> <input value={message} onChange={e => setMessage(e.target.value)} /> </> ); } export default function App() { const [roomId, setRoomId] = useState('general'); return ( <> <label> Choose the chat room:{' '} <select value={roomId} onChange={e => setRoomId(e.target.value)} > <option value="general">general</option> <option value="travel">travel</option> <option value="music">music</option> </select> </label> <hr /> <ChatRoom roomId={roomId} /> </> ); }
createOptions ι’ζ°γγ¨γγ§γ―γε
γ§οΏ½?οΏ½ηΎ©γγγγγ«γγοΏ½?γ§γγ¨γγ§γ―γθͺδ½γ― roomId ζεεγ«οΏ½?γΏδΎεγγγγ¨γ«γͺγγΎγγγοΏ½?οΏ½?ζ£γ«γγγε
₯εζ¬γ«ε
₯εγγ¦γγγ£γγγεζ₯ηΆγγγͺγγͺγγΎγγεγ¬γ³γγΌζγ«εδ½ζγγγι’ζ°γ¨γ―η°γͺγγroomId οΏ½?γγγͺζεεγ―δ»οΏ½?ε€γ«θ¨οΏ½?οΏ½γγͺγιγε€ζ΄γγγΎγγγδΎεε€οΏ½?ει€γ«γ€γγ¦θ©³γγγ―γγ‘γγ
γ¨γγ§γ―γγγζζ°οΏ½? props γ¨ state γθͺγΏεγ
γγγ©γ«γγ§γ―γγ¨γγ§γ―γγγγͺγ’γ―γγ£γγͺε€γθͺγΏεγγ¨γγ―γγγγδΎεε€γ¨γγ¦θΏ½ε γγεΏ θ¦γγγγΎγγγγγ«γγγγ¨γγ§γ―γγ―γοΏ½?ε€οΏ½?ε€ζ΄γ«ε―Ύγγ¦γεεΏγγγγγ¨γδΏθ¨ΌγγγΎγγγ»γ¨γγ©οΏ½?δΎεε€γ«γ€γγ¦γ―γγγγζγζεγ§γγ
γγ γγζγ«γ―γεεΏγγγγγ«ζζ°οΏ½? props γ state γ γ¨γγ§γ―γε γγθͺγΏεγγγγγ¨γγγγ§γγγγδΎγγ°γγ·γ§γγγ³γ°γ«γΌγε οΏ½?γ’γ€γγ ζ°γγγΌγΈθ¨ͺεγγ¨γ«θ¨ι²γγε ΄εγζ³εγγ¦γΏγ¦γγ γγγ
function Page({ url, shoppingCart }) {
useEffect(() => {
logVisit(url, shoppingCart.length);
}, [url, shoppingCart]); // β
All dependencies declared
// ...
}url οΏ½?ε€ζ΄γγ¨γ«ζ°γγγγΌγΈθ¨ͺεγθ¨ι²γγγγγshoppingCart οΏ½?ε€ζ΄οΏ½?γΏγ§γ―θ¨ι²γγγγͺγε ΄εγ―γ©γγγγ°γγοΏ½?γ§γγγγοΌ γͺγ’γ―γγ£γγ«γΌγ«γ«εγγγγ¨γͺγ shoppingCart γδΎει
εγγι€ε€γγγγ¨γ―γ§γγΎγγγγγγγγ¨γγ§γ―γε
γγεΌγ°γγγ³γΌγοΏ½?δΈι¨γ§γγγ«γγγγγγγγοΏ½?γ³γΌγγε€ζ΄γ«γεεΏγγγͺγγγ¨γη€Ίγγγ¨γγ§γγΎγγuseEffectEvent γγγ―γδ½Ώη¨γγ¦γγ¨γγ§γ―γγ€γγ³γ (effect event) γοΏ½?οΏ½θ¨γγshoppingCart γθͺγΏεγγ³γΌγγγοΏ½?ε
ι¨γ«η§»εγγ¦γγ γγγ
function Page({ url, shoppingCart }) {
const onVisit = useEffectEvent(visitedUrl => {
logVisit(visitedUrl, shoppingCart.length)
});
useEffect(() => {
onVisit(url);
}, [url]); // β
All dependencies declared
// ...
}γ¨γγ§γ―γγ€γγ³γγ―γͺγ’γ―γγ£γγ§γͺγ―γγγγγγͺγοΏ½?γ¨γγ§γ―γοΏ½?δΎει
εγγγ―εΈΈγ«ι€γεΏ
θ¦γγγγΎγγγγγ«γγγιγͺγ’γ―γγ£γγͺγ³γΌγοΌζζ°οΏ½? props γ state οΏ½?ε€γθͺγγγ¨γγ§γγγ³γΌγοΌγγ¨γγ§γ―γγ€γγ³γε
γ«ε
₯γγγγ¨γγ§γγΎγγonVisit οΏ½?δΈγ§ shoppingCart γθͺγγγ¨γ§γshoppingCart γγ¨γγ§γ―γγεοΏ½?οΏ½θ‘γγγγ¨γγͺγγͺγγΎγγ
γ΅γΌγγ¨γ―γ©γ€γ’γ³γγ§η°γͺγγ³γ³γγ³γγ葨瀺γγ
γδ½ΏγοΏ½?γ’γγͺγγ΅γΌγγ¬γ³γγͺγ³γ°γοΌη΄ζ₯γͺγγγγ¬γΌγ γ―γΌγ―η΅η±γ§οΌδ½Ώη¨γγ¦γγε ΄εγγ³γ³γγΌγγ³γγ― 2 οΏ½?ι‘οΏ½?η°ε’γ§γ¬γ³γγΌγγγΎγγγ΅γΌγδΈγ§γ―γεζ HTML γηζγγγγγ«γ¬γ³γγΌγγγΎγγγ―γ©γ€γ’γ³γδΈγ§γ―γReact γγοΏ½? HTML γ«γ€γγ³γγγ³γγ©γγ’γΏγγγγγγγ«εεΊ¦γ¬γ³γγΌγ³γΌγγοΏ½?οΏ½θ‘γγΎγγγγγγγγ€γγ¬γΌγ·γ§γ³γεδ½γγγγγ«γ―εεγ¬γ³γγΌοΏ½?εΊεγγ―γ©γ€γ’γ³γγ¨γ΅γΌγοΏ½?δΈ‘ζΉγ§εδΈγ§γͺγγγ°γͺγγͺγηη±γ§γγ
γΎγγ«γγ―γ©γ€γ’γ³γε΄γ§η°γͺγγ³γ³γγ³γγ葨瀺γγεΏ
θ¦γγγε ΄εγγγγΎγγγγ¨γγ°γγ’γγͺγ localStorage γγγγΌγΏγθͺγΏθΎΌγε ΄εγγ΅γΌγδΈγ§γ―γγγθ‘γγγ¨γγ§γγΎγγγγγγ―δ»₯δΈοΏ½?ζΉζ³γ§οΏ½?οΏ½θ£
γ§γγΎγγ
function MyComponent() {
const [didMount, setDidMount] = useState(false);
useEffect(() => {
setDidMount(true);
}, []);
if (didMount) {
// ... return client-only JSX ...
} else {
// ... return initial JSX ...
}
}γ’γγͺγγγΌγγγγ¦γγιγγ¦γΌγΆγ―εζγ¬γ³γγΌοΏ½?εΊεγ葨瀺γγΎγγγγΌγγ¨γγ€γγ¬γΌγ·γ§γ³γοΏ½?οΏ½δΊγγγγγ¨γγ§γ―γγοΏ½?οΏ½θ‘γγγdidMount γ true γ«γ»γγγγγεγ¬γ³γγΌγγγͺγ¬γγγΎγγγγγ«γγγγ―γ©γ€γ’γ³γε°η¨οΏ½?γ¬γ³γγΌεΊεγ«εγζΏγγγΎγγγ¨γγ§γ―γγ―γ΅γΌγδΈγ§γ―οΏ½?οΏ½θ‘γγγͺγγγγεεγ΅γΌγγ¬γ³γγΌζγ«γ― didMount γ― false οΏ½?γΎγΎγ«γͺγγΎγγ
γοΏ½?γγΏγΌγ³γ―η―εΊ¦γζγ£γ¦δ½Ώη¨γγ¦γγ γγγι γζ₯ηΆοΏ½?γ¦γΌγΆγ―εζγ³γ³γγ³γγγγͺγι·γζιγε ΄εγ«γγ£γ¦γ―ζ°η§δ»₯δΈθ‘¨η€Ίγγγγ¨γ«γͺγγΎγγγͺοΏ½?γ§γ³γ³γγΌγγ³γοΏ½?θ¦γοΏ½?γ«ιεζγδΈγγε€ζ΄γγγͺγγγγ«γγ¦γγ γγγε€γοΏ½?ε ΄εγCSS γ§ζ‘δ»Άδ»γγ«η°γͺγγοΏ½?γ葨瀺γγγγ¨γ§γγοΏ½?γγγͺγγ¨γ―γγͺγγ¦γγγͺγγΎγγ
γγ©γγ«γ·γ₯γΌγγ£γ³γ°
γ³γ³γγΌγγ³γοΏ½?γγ¦γ³γζγ«γ¨γγ§γ―γγ 2 εοΏ½?οΏ½θ‘γγγ
Strict Mode γγͺγ³οΏ½?ε ΄εγιηΊζγ« React γ―οΏ½?οΏ½ιοΏ½?γ»γγγ’γγοΏ½?εγ«γγ»γγγ’γγγ¨γ―γͺγΌγ³γ’γγγγγδΈεΊ¦οΏ½?οΏ½θ‘γγΎγγ
γγγ―γγ¨γγ§γ―γοΏ½?γγΈγγ―γζ£γγοΏ½?οΏ½θ£ γγγ¦γγγγ¨γη’ΊθͺγγγγοΏ½?γΉγγ¬γΉγγΉγγ§γγγγγοΏ½?γ«θ¦γγει‘γεΌγθ΅·γγε ΄εγγ―γͺγΌγ³γ’γγι’ζ°γ«δΈι¨οΏ½?γγΈγγ―γζ¬ γγ¦γγΎγγγ―γͺγΌγ³γ’γγι’ζ°γ―γγ»γγγ’γγι’ζ°γθ‘γ£γ¦γγγγ¨γεζ’γͺγγε γ«ζ»γεΏ θ¦γγγγΎγγεΊζ¬εεγ―γγ¦γΌγΆγγ»γγγ’γγγδΈεΊ¦εΌγ°γγε ΄εοΌζ¬ηͺη°ε’οΏ½?ε ΄εοΌγ¨γγ»γγγ’γγ β γ―γͺγΌγ³γ’γγ β γ»γγγ’γγγ¨γγγ·γΌγ±γ³γΉγ§εΌγ°γγε ΄εοΌιηΊη°ε’οΏ½?ε ΄εοΌγ§γιγγθ¦εγγγγ¦γ―γγγͺγγγ¨γγγγ¨γ§γγ
γ©οΏ½?γγγ«γγ°γθ¦γ€γγοΏ½?γ«ε½Ήη«γ€γ γ¨γγγΈγγ―γοΏ½?ζ£γγζΉζ³ γ«γ€γγ¦θ©³γγθͺγγ
γ¨γγ§γ―γγεγ¬γ³γγΌγγ¨γ«οΏ½?οΏ½θ‘γγγ
γΎγγδΎει εοΏ½?ζοΏ½?οΏ½γεΏγγ¦γγͺγγη’Ίθͺγγ¦γγ γγγ
useEffect(() => {
// ...
}); // π© No dependency array: re-runs after every render!δΎει εγζοΏ½?οΏ½γγ¦γγγ«γγγγγγγγ¨γγ§γ―γγγ«γΌγγ§εοΏ½?οΏ½θ‘γγγε ΄εγγγγ―εγ¬γ³γγΌγγ¨γ«δΎεγγε€οΏ½?γ©γγγε€γγ£γ¦γγγγγ§γγ
γοΏ½?ει‘γ―γζεγ§δΎεγγε€γγ³γ³γ½γΌγ«γ«γγ°εΊεγγγγ¨γ§γγγγ°γ§γγΎγγ
useEffect(() => {
// ..
}, [serverUrl, roomId]);
console.log([serverUrl, roomId]);欑γ«γγ³γ³γ½γΌγ«δΈοΏ½?η°γͺγεγ¬γ³γγΌγγ葨瀺γγγι
εγε³γ―γͺγγ―γγγγγγγ§ βStore as a global variableβ γιΈζγγΎγγζεοΏ½?γοΏ½?γ temp1 γ¨γγ¦δΏεγγγ2 ηͺοΏ½?οΏ½?γοΏ½?γ temp2 γ¨γγ¦δΏεγγγγ¨γγγ¨γδ»₯δΈοΏ½?γγγ«γγ©γ¦γΆοΏ½?γ³γ³γ½γΌγ«γδ½Ώγ£γ¦γδΈ‘ζΉοΏ½?ι
εγ§γγγγοΏ½?ε€γεγγγ©γγγη’Ίθͺγ§γγΎγγ
Object.is(temp1[0], temp2[0]); // Is the first dependency the same between the arrays?
Object.is(temp1[1], temp2[1]); // Is the second dependency the same between the arrays?
Object.is(temp1[2], temp2[2]); // ... and so on for every dependency ...εγ¬γ³γγΌγγ¨γ«ε€οΏ½?ε€γγδΎεε€γθ¦γ€γγ£γε ΄εγιεΈΈγ―欑�?ζΉζ³οΏ½?γγγγγ§οΏ½?ζ£γ§γγΎγγ
- γ¨γγ§γ―γγγοΏ½?εεοΏ½? state γ«εΊγ₯γ state οΏ½?ζ΄ζ°
- γͺγγΈγ§γ―γεοΏ½?δΈθ¦γͺδΎεε€γει€γγ
- ι’ζ°εοΏ½?δΈθ¦γͺδΎεε€γει€γγ
- γ¨γγ§γ―γγγζζ°οΏ½? props γ¨ state γθͺγΏεγ
ζεΎοΏ½?ζοΏ½?οΏ½γ¨γγ¦γδΈθ¨οΏ½?ζΉζ³γγγΎγγγγͺγγ£γε ΄εγγοΏ½?ε€γδ½γ£γ¦γγγ¨γγγ useMemo γΎγγ―οΌι’ζ°οΏ½?ε ΄εοΌuseCallback γ§γ©γγγγ¦γγ γγγ
γ¨γγ§γ―γγη‘ιγ«γΌγγ§εοΏ½?οΏ½θ‘γγηΆγγ
γ¨γγ§γ―γγη‘ιγ«γΌγγ§οΏ½?οΏ½θ‘γγγε ΄εγδ»₯δΈοΏ½? 2 γ€οΏ½?ζ‘δ»Άγζη«γγ¦γγγ―γγ§γγ
- γ¨γγ§γ―γγδ½γγοΏ½? state γζ΄ζ°γγ¦γγγ
- γοΏ½? state ζ΄ζ°γ«γγεγ¬γ³γγΌγηΊηγγγγγ«γγγ¨γγ§γ―γοΏ½?δΎει εγε€ζ΄γγγ¦γγγ
ει‘γοΏ½?ζ£γγεγ«γγ¨γγ§γ―γγε€ι¨γ·γΉγγ οΌDOMγγγγγ―γΌγ―γγ΅γΌγγγΌγγ£οΏ½?γ¦γ£γΈγ§γγγͺγ©οΌγ«ζ₯ηΆγγ¦γγγγ©γγγη’Ίθͺγγ¦γγ γγγγ¨γγ§γ―γγ state γθ¨οΏ½?οΏ½γγεΏ θ¦γγγηη±γ―δ½γ§γγοΌ ε€ι¨γ·γΉγγ γ¨εζγγγγγ§γγοΌ γγγ¨γγγ’γγͺγ±γΌγ·γ§γ³οΏ½?γγΌγΏγγγΌγγγγ§οΏ½?οΏ½ηγγγγ¨γγ¦γγοΏ½?γ§γγγγοΌ
ε€ι¨γ·γΉγγ γγͺγε ΄εγγγγγγ¨γγ§γ―γγει€γγγγ¨γ§γγΈγγ―γη°‘η₯εγγγγγ©γγγζ€θ¨γγ¦γγ γγγ
γγζ¬ε½γ«ε€ι¨γ·γΉγγ γ¨εζγγ¦γγε ΄εγ―γγ¨γγ§γ―γγγγ€γγ©οΏ½?γγγͺζ‘δ»ΆδΈγ§ state γζ΄ζ°γγεΏ θ¦γγγγθγγ¦γΏγ¦γγ γγγδ½γγγ³γ³γγΌγγ³γοΏ½?θ¦θ¦ηγͺεΊεγ«ε½±ιΏγδΈγγε€ζ΄γγγοΏ½?γ§γγγγοΌ γ¬γ³γγΌγ«δ½Ώη¨γγγͺγγγΌγΏγοΏ½?οΏ½ηγγεΏ θ¦γγγε ΄εγ―γrefοΌεγ¬γ³γγΌγγγͺγ¬γγͺγοΌοΏ½?ζΉγι©εγγγγγΎγγγγ¨γγ§γ―γγεΏ θ¦δ»₯δΈγ« state γζ΄ζ°οΌγγ¦εγ¬γ³γγΌγγγͺγ¬οΌγγ¦γγͺγγγ¨γη’Ίθͺγγ¦γγ γγγ
ζεΎγ«γγ¨γγ§γ―γγι©εγͺγΏγ€γγ³γ°γ§ state γζ΄ζ°γγ¦γγγοΏ½?οΏ½?γγγγ§γη‘ιγ«γΌγγοΏ½?οΏ½γ£γ¦γγε ΄εγ―γγοΏ½? state οΏ½?ζ΄ζ°γ«γγγ¨γγ§γ―γοΏ½?δΎει εοΏ½?γ©γγγε€ζ΄γγγ¦γγγγγ§γγδΎει εοΏ½?ε€ζ΄γγγγγ°γγζΉζ³γη’Ίθͺγγ¦γγ γγγ
γ³γ³γγΌγγ³γγγ’γ³γγ¦γ³γγγγ¦γγͺγοΏ½?γ«γ―γͺγΌγ³γ’γγγγΈγγ―γοΏ½?οΏ½θ‘γγγ
γ―γͺγΌγ³γ’γγι’ζ°γ―γγ’γ³γγ¦γ³γζγ γγ§γͺγγδΎει εγε€ζ΄γγγεΎοΏ½?εγ¬γ³γγΌεΎγ«γοΏ½?οΏ½θ‘γγγΎγγγΎγγιηΊδΈγ«γ―γReact γγ³γ³γγΌγγ³γοΏ½?γγ¦γ³γη΄εΎγ«γγ»γγγ’γγ+γ―γͺγΌγ³γ’γγγ 1 εθΏ½ε γ§οΏ½?οΏ½θ‘γγΎγγ
ε―ΎεΏγγγ»γγγ’γγγ³γΌγοΏ½?γͺγγ―γͺγΌγ³γ’γγγ³γΌγγγζγ‘οΏ½?ε ΄εγιεΈΈγ―γ³γΌγοΏ½?ει‘γγγγΎγγ
useEffect(() => {
// π΄ Avoid: Cleanup logic without corresponding setup logic
return () => {
doSomething();
};
}, []);γ―γͺγΌγ³γ’γγγγΈγγ―γ―γ»γγγ’γγγγΈγγ―γ¨γε―Ύη§°ηγγ§γγγγ»γγγ’γγγθ‘γ£γγγ¨γεζ’γͺγγε γ«ζ»γεΏ θ¦γγγγΎγγ
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => {
connection.disconnect();
};
}, [serverUrl, roomId]);γ¨γγ§γ―γγ葨瀺γ«ι’γγγγ¨γθ‘γ£γ¦γγγοΏ½?οΏ½θ‘εγ«γ‘γγ€γγθ¦γγγ
γ¨γγ§γ―γγγγ©γ¦γΆοΏ½?η»ι’ζη»γγγγγ―γγεΏ
θ¦γγγε ΄εγ―γuseEffect οΏ½?代γγγ« useLayoutEffect γδ½Ώη¨γγ¦γγ γγγγγ γγγγγ―γ»γ¨γγ©οΏ½?γ¨γγ§γ―γγ«γ―εΏ
θ¦γͺγγ¨γγγγ¨γ«ζ³¨ζγγ¦γγ γγγγγγ―γγγ©γ¦γΆζη»οΏ½?εγ«γ¨γγ§γ―γγοΏ½?οΏ½θ‘γγγγ¨γιθ¦γͺε ΄εγ«οΏ½?γΏεΏ
θ¦γ§γγδΎγγ°γγ¦γΌγΆγγγΌγ«γγγγθ¦γεγ«γγγΌγ«γγγοΏ½?γ΅γ€γΊγζΈ¬οΏ½?οΏ½γγ¦ι
οΏ½?γγγγγ«δ½Ώη¨γγΎγγ