useEffect γ―γ€γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγ‚’ε€–ιƒ¨γ‚·γ‚Ήγƒ†γƒ γ¨εŒζœŸγ•γ›γ‚‹γŸγ‚οΏ½? React フックです。

useEffect(setup, dependencies?)

γƒͺフゑレンス

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 ぀�?εΌ•ζ•°γ‚’ζΈ‘γ™εΏ…θ¦γŒγ‚γ‚ŠγΎγ™γ€‚

  1. システムにζŽ₯ηΆšγ™γ‚‹γ‚»γƒƒγƒˆγ‚’γƒƒγƒ—γ‚³γƒΌγƒ‰γ‚’ε«γ‚€γ‚»γƒƒγƒˆγ‚’γƒƒγƒ—ι–’ζ•°γ€‚
    • そ�?γ‚·γ‚Ήγƒ†γƒ γ‹γ‚‰εˆ‡ζ–­γ™γ‚‹γ‚―γƒͺーンをップコードを含むクγƒͺγƒΌγƒ³γ‚’γƒƒγƒ—ι–’ζ•°γ‚’θΏ”γ™εΏ…θ¦γŒγ‚γ‚ŠγΎγ™γ€‚
  2. γ“γ‚Œγ‚‰οΏ½?ι–’ζ•°ε†…γ§δ½Ώη”¨γ•γ‚Œγ‚‹γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγ‹γ‚‰οΏ½?すべて�?ε€€γ‚’ε«γ‚“γ δΎε­˜ε€€οΏ½?γƒͺγ‚Ήγƒˆγ€‚

React γ―εΏ…θ¦γ«εΏœγ˜γ¦γ‚»γƒƒγƒˆγ‚’γƒƒγƒ—ι–’ζ•°γ¨γ‚―γƒͺγƒΌγƒ³γ‚’γƒƒγƒ—ι–’ζ•°γ‚’ε‘Όγ³ε‡Ίγ—γ€γ“γ‚Œγ―θ€‡ζ•°ε›žθ‘Œγ‚γ‚Œγ‚‹γ“γ¨γŒγ‚γ‚ŠγΎγ™γ€‚

  1. γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγŒγƒšγƒΌγ‚Έγ«θΏ½εŠ οΌˆγƒžγ‚¦γƒ³γƒˆοΌ‰γ•γ‚Œγ‚‹γ¨γ€γ‚»γƒƒγƒˆγ‚’γƒƒγƒ—γ‚³γƒΌγƒ‰γŒοΏ½?οΏ½θ‘Œγ•γ‚ŒγΎγ™γ€‚
  2. δΎε­˜ε€€γŒε€‰ζ›΄γ•γ‚ŒγŸδΈŠγ§γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγŒε†γƒ¬γƒ³γƒ€γƒΌγ•γ‚Œγ‚‹εΊ¦γ«οΌš
    • γΎγšγ€ε€γ„ props と state でクγƒͺγƒΌγƒ³γ‚’γƒƒγƒ—γ‚³γƒΌγƒ‰γŒοΏ½?οΏ½θ‘Œγ•γ‚ŒγΎγ™γ€‚
    • 欑に、新しい props と state γ§γ‚»γƒƒγƒˆγ‚’γƒƒγƒ—γ‚³γƒΌγƒ‰γŒοΏ½?οΏ½θ‘Œγ•γ‚ŒγΎγ™γ€‚
  3. γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγŒγƒšγƒΌγ‚Έγ‹γ‚‰ε‰Šι™€οΌˆγ‚’γƒ³γƒžγ‚¦γƒ³γƒˆοΌ‰γ•γ‚Œγ‚‹γ¨γ€ζœ€εΎŒγ«γ‚―γƒͺγƒΌγƒ³γ‚’γƒƒγƒ—γ‚³γƒΌγƒ‰γŒοΏ½?οΏ½θ‘Œγ•γ‚ŒγΎγ™γ€‚

上記�?例でこ�?シーケンスをθͺ¬ζ˜Žγ—ましょう。

上記�? ChatRoom γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγŒγƒšγƒΌγ‚Έγ«θΏ½εŠ γ•γ‚Œγ‚‹γ¨γ€serverUrl と roomId οΏ½?εˆζœŸε€€γ‚’δ½Ώγ£γ¦γƒγƒ£γƒƒγƒˆγƒ«γƒΌγƒ γ«ζŽ₯ηΆšγ—γΎγ™γ€‚serverUrl または roomId γŒε†γƒ¬γƒ³γƒ€γƒΌοΏ½?η΅ζžœγ¨γ—γ¦ε€‰ζ›΄γ•γ‚Œγ‚‹ε ΄εˆοΌˆδΎ‹γˆγ°γ€γƒ¦γƒΌγ‚ΆγŒγƒ‰γƒ­γƒƒγƒ—γƒ€γ‚¦γƒ³γ§εˆ₯οΏ½?γƒγƒ£γƒƒγƒˆγƒ«γƒΌγƒ γ‚’ιΈζŠžγ—γŸε ΄εˆοΌ‰γ€γ‚γͺた�?γ‚¨γƒ•γ‚§γ‚―γƒˆγ―δ»₯前�?γƒ«γƒΌγƒ γ‹γ‚‰εˆ‡ζ–­γ—γ€ζ¬‘οΏ½?ルームにζŽ₯ηΆšγ—γΎγ™γ€‚ChatRoom γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγŒγƒšγƒΌγ‚Έγ‹γ‚‰ε‰Šι™€γ•γ‚Œγ‚‹γ¨γ€γ‚γͺた�?γ‚¨γƒ•γ‚§γ‚―γƒˆγ―ζœ€εΎŒοΏ½?εˆ‡ζ–­γ‚’θ‘Œγ„γΎγ™γ€‚

γƒγ‚°γ‚’θ¦‹γ€γ‘ε‡Ίγ™γŸγ‚γ«γ€ι–‹η™ΊδΈ­γ«γ― React γ―γ‚»γƒƒγƒˆγ‚’γƒƒγƒ—γ¨γ‚―γƒͺγƒΌγƒ³γ‚’γƒƒγƒ—γ‚’γ€γ‚»γƒƒγƒˆγ‚’γƒƒγƒ—οΏ½?前に 1 ε›žδ½™εˆ†γ«οΏ½?οΏ½θ‘Œγ—γΎγ™γ€‚γ“γ‚Œγ―γ€γ‚¨γƒ•γ‚§γ‚―γƒˆοΏ½?γƒ­γ‚Έγƒƒγ‚―γŒζ­£γ—γοΏ½?οΏ½θ£…γ•γ‚Œγ¦γ„γ‚‹γ“γ¨γ‚’η’Ίθͺγ™γ‚‹γ‚Ήγƒˆγƒ¬γ‚Ήγƒ†γ‚Ήγƒˆγ§γ™γ€‚γ“γ‚ŒγŒοΏ½?γ«θ¦‹γˆγ‚‹ε•ι‘Œγ‚’εΌ•γθ΅·γ“γ™ε ΄εˆγ€γ‚―γƒͺーンをップ閒数に一部�?γƒ­γ‚Έγƒƒγ‚―γŒζ¬ γ‘γ¦γ„γΎγ™γ€‚γ‚―γƒͺγƒΌγƒ³γ‚’γƒƒγƒ—ι–’ζ•°γ―γ€γ‚»γƒƒγƒˆγ‚’γƒƒγƒ—ι–’ζ•°γŒθ‘Œγ£γ¦γ„γŸγ“γ¨γ‚’εœζ­’γͺγ„γ—ε…ƒγ«ζˆ»γ™εΏ…θ¦γŒγ‚γ‚ŠγΎγ™γ€‚εŸΊζœ¬γƒ«γƒΌγƒ«γ¨γ—γ¦γ€γƒ¦γƒΌγ‚Άγ―γ‚»γƒƒγƒˆγ‚’γƒƒγƒ—γŒδΈ€εΊ¦γ—γ‹ε‘Όγ°γ‚Œγ¦γ„γͺγ„οΌˆζœ¬η•ͺη’°ε’ƒοΏ½?ε ΄εˆοΌ‰γ‹γ€γ‚»γƒƒγƒˆγ‚’γƒƒγƒ— β†’ γ‚―γƒͺーンをップ β†’ γ‚»γƒƒγƒˆγ‚’γƒƒγƒ—οΏ½?γ‚·γƒΌγ‚±γƒ³γ‚ΉοΌˆι–‹η™Ίη’°ε’ƒοΏ½?ε ΄εˆοΌ‰γ§ε‘Όγ°γ‚Œγ¦γ„γ‚‹γ‹γ‚’εŒΊεˆ₯できγͺγ„γ‚ˆγ†γ«γ™γ‚‹εΏ…θ¦γŒγ‚γ‚ŠγΎγ™γ€‚δΈ€θˆ¬ηš„γͺ解決法を参照してください。

ε„γ‚¨γƒ•γ‚§γ‚―γƒˆγ‚’η‹¬η«‹γ—γŸγƒ—γƒ­γ‚»γ‚Ήγ¨γ—γ¦θ¨˜θΏ°γ™γ‚‹γ‚ˆγ†γ«γ—γ€δΈ€ε›žοΏ½?γ‚»γƒƒγƒˆγ‚’γƒƒγƒ—οΌγ‚―γƒͺーンをップ�?γ‚΅γ‚€γ‚―γƒ«γ γ‘γ‚’θ€ƒγˆγ‚‹γ‚ˆγ†γ«γ—γ¦γγ γ•γ„γ€‚γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγŒηΎεœ¨γƒžγ‚¦γƒ³γƒˆγ€ζ›΄ζ–°γ€γ‚’γƒ³γƒžγ‚¦γƒ³γƒˆοΏ½?γ©γ‚Œγ‚’θ‘Œγ£γ¦γ„γ‚‹γ‹γ‚’θ€ƒοΏ½?γ™γΉγγ§γ―γ‚γ‚ŠγΎγ›γ‚“γ€‚γ‚»γƒƒγƒˆγ‚’γƒƒγƒ—γƒ­γ‚Έγƒƒγ‚―γŒζ­£γ—γγ‚―γƒͺγƒΌγƒ³γ‚’γƒƒγƒ—γƒ­γ‚Έγƒƒγ‚―γ¨γ€Œε―ΎεΏœγ€γ•γ‚Œγ‚‹γ“γ¨γ§γ€γ‚¨γƒ•γ‚§γ‚―γƒˆγ―γ‚»γƒƒγƒˆγ‚’γƒƒγƒ—γ¨γ‚―γƒͺγƒΌγƒ³γ‚’γƒƒγƒ—γ‚’εΏ…θ¦γ«εΏœγ˜γ¦δ½•εΊ¦οΏ½?οΏ½θ‘Œγ—γ¦γ‚‚ε•ι‘ŒγŒθ΅·γγͺい、堅牒γͺγ‚‚οΏ½?とγͺγ‚ŠγΎγ™γ€‚

補袳

γ‚¨γƒ•γ‚§γ‚―γƒˆγ―γ€γ‚³γƒ³γƒγƒΌγƒγƒ³γƒˆγ‚’ε€–ιƒ¨γ‚·γ‚Ήγƒ†γƒ οΌˆγƒγƒ£γƒƒγƒˆγ‚΅γƒΌγƒ“γ‚ΉοΏ½?γ‚ˆγ†γͺγ‚‚οΏ½?οΌ‰γ¨εŒζœŸγ•γ›γ‚‹γŸγ‚γ«δ½Ώγ„γΎγ™γ€‚γ“γ“γ§γ„γ†ε€–ιƒ¨γ‚·γ‚Ήγƒ†γƒ γ¨γ―γ€React γŒεˆΆεΎ‘γ—γ¦γ„γͺいコード�?δΈ€ιƒ¨γ§γ€γŸγ¨γˆγ°δ»₯δΈ‹οΏ½?γ‚ˆγ†γͺγ‚‚οΏ½?です。

  • setInterval() と clearInterval() で�?οΏ½η†γ•γ‚Œγ‚‹γ‚Ώγ‚€γƒžγƒΌγ€‚
  • window.addEventListener() と window.removeEventListener() γ‚’δ½Ώγ£γŸγ‚€γƒ™γƒ³γƒˆγ‚΅γƒ–γ‚Ήγ‚―γƒͺプション。
  • animation.start() と animation.reset() οΏ½?γ‚ˆγ†γͺ API γ‚’ζŒγ€γ‚΅γƒΌγƒ‰γƒ‘γƒΌγƒ†γ‚£οΏ½?をニパーションラむブラγƒͺ。

倖部システムにζŽ₯ηΆšγ—γ¦γ„γͺγ„ε ΄εˆγ―γ€ζγ‚‰γγ‚¨γƒ•γ‚§γ‚―γƒˆγ―δΈθ¦γ§γ™γ€‚

倖部システムへ�?ζŽ₯ηΆšδΎ‹

δΎ‹ 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 γŒε€‰ζ›΄γ•γ‚ŒγŸε ΄εˆγ§γ‚‚ε†οΏ½?οΏ½θ‘Œγ•γ‚ŒγΎγ›γ‚“γ€‚

落とし穴

ζ—’ε­˜οΏ½?γ‚³γƒΌγƒ‰γƒ™γƒΌγ‚ΉγŒγ‚γ‚‹ε ΄εˆγ€δ»₯δΈ‹οΏ½?γ‚ˆγ†γ«γ—γ¦γƒͺγƒ³γ‚Ώγ‚’ι»™γ‚‰γ›γ¦γ„γ‚‹γ‚¨γƒ•γ‚§γ‚―γƒˆγ‚’θ¦‹γ‹γ‘γ‚‹γ‹γ‚‚γ—γ‚ŒγΎγ›γ‚“γ€‚

useEffect(() => {
// ...
// πŸ”΄ Avoid suppressing the linter like this:
// eslint-ignore-next-line react-hooks/exhaustive-deps
}, []);

δΎε­˜ι…εˆ—γŒγ‚³γƒΌγƒ‰γ¨δΈ€θ‡΄γ—γͺγ„ε ΄εˆγ€γƒγ‚°γŒη™Ίη”Ÿγ™γ‚‹γƒͺγ‚Ήγ‚―γŒι«˜γγͺγ‚ŠγΎγ™γ€‚γƒͺγƒ³γ‚Ώγ‚’ζŠ‘εˆΆγ™γ‚‹γ“γ¨γ§γ€γ‚¨γƒ•γ‚§γ‚―γƒˆγŒδΎε­˜γ™γ‚‹ε€€γ«γ€γ„γ¦ React γ«γ€Œε˜˜γ€γ‚’γ€γγ“γ¨γ«γͺγ‚ŠγΎγ™γ€‚δ»£γ‚γ‚Šγ«γγ‚Œγ‚‰γŒδΈθ¦γ§γ‚γ‚‹γ“γ¨γ‚’θ¨Όζ˜Žγ—γ¦γγ γ•γ„γ€‚

γƒͺをクティブγͺδΎε­˜ε€€οΏ½?ι…εˆ—γ‚’ζΈ‘γ™δΎ‹

δΎ‹ 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 γ‚’θͺ­γΏε–γ‚‹

Under Construction

こ�?セクションでは、まだ�?οΏ½οΏ½?οΏ½γ—γŸγƒγƒΌγ‚Έγƒ§γƒ³οΏ½? React でγƒͺγƒͺγƒΌγ‚Ήγ•γ‚Œγ¦γ„γͺい�?οΏ½ι¨“ηš„γͺ API に぀いてθͺ¬ζ˜Žγ—ます。

γƒ‡γƒ•γ‚©γƒ«γƒˆγ§γ―γ€γ‚¨γƒ•γ‚§γ‚―γƒˆγ‹γ‚‰γƒͺをクティブγͺε€€γ‚’θͺ­γΏε–γ‚‹γ¨γγ―γ€γγ‚Œγ‚’δΎε­˜ε€€γ¨γ—γ¦θΏ½εŠ γ™γ‚‹εΏ…θ¦γŒγ‚γ‚ŠγΎγ™γ€‚γ“γ‚Œγ«γ‚ˆγ‚Šγ€γ‚¨γƒ•γ‚§γ‚―γƒˆγ―γοΏ½?ε€€οΏ½?ε€‰ζ›΄γ«ε―Ύγ—γ¦γ€ŒεεΏœγ€γ™γ‚‹γ“γ¨γŒδΏθ¨Όγ•γ‚ŒγΎγ™γ€‚γ»γ¨γ‚“γ©οΏ½?δΎε­˜ε€€γ«γ€γ„γ¦γ―γ€γγ‚ŒγŒζœ›γ‚€ζŒ™ε‹•γ§γ™γ€‚

γŸγ γ—γ€ζ™‚γ«γ―γ€ŒεεΏœγ€γ‚’γ›γšγ«ζœ€ζ–°οΏ½? 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 ...

再レンダーごとに倀�?ε€‰γ‚γ‚‹δΎε­˜ε€€γŒθ¦‹γ€γ‹γ£γŸε ΄εˆγ€ι€šεΈΈγ―ζ¬‘οΏ½?方法�?γ„γšγ‚Œγ‹γ§οΏ½?正できます。

ζœ€εΎŒοΏ½?手�?οΏ½γ¨γ—γ¦γ€δΈŠθ¨˜οΏ½?ζ–Ήζ³•γŒγ†γΎγγ„γ‹γͺγ‹γ£γŸε ΄εˆγ€γοΏ½?ε€€γ‚’δ½œγ£γ¦γ„γ‚‹γ¨γ“γ‚γ‚’ 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 γ‚’δ½Ώη”¨γ—γ¦γγ γ•γ„γ€‚γŸγ γ—γ€γ“γ‚Œγ―γ»γ¨γ‚“γ©οΏ½?γ‚¨γƒ•γ‚§γ‚―γƒˆγ«γ―εΏ…θ¦γͺγ„γ¨γ„γ†γ“γ¨γ«ζ³¨ζ„γ—γ¦γγ γ•γ„γ€‚γ“γ‚Œγ―γ€γƒ–γƒ©γ‚¦γ‚Άζη”»οΏ½?ε‰γ«γ‚¨γƒ•γ‚§γ‚―γƒˆγ‚’οΏ½?οΏ½θ‘Œγ™γ‚‹γ“γ¨γŒι‡θ¦γͺ場合に�?γΏεΏ…θ¦γ§γ™γ€‚δΎ‹γˆγ°γ€γƒ¦γƒΌγ‚ΆγŒγƒ„γƒΌγƒ«γƒγƒƒγƒ—γ‚’θ¦‹γ‚‹ε‰γ«γ€γƒ„γƒΌγƒ«γƒγƒƒγƒ—οΏ½?γ‚΅γ‚€γ‚Ίγ‚’ζΈ¬οΏ½?�して配�?γ™γ‚‹γŸγ‚γ«δ½Ώη”¨γ—γΎγ™γ€‚