useEffectEvent は、エフェクトから非ãƒĒã‚ĸã‚¯ãƒ†ã‚Ŗãƒ–ãĒãƒ­ã‚¸ãƒƒã‚¯ã‚’ã€ã‚¨ãƒ•ã‚§ã‚¯ãƒˆã‚¤ãƒ™ãƒŗãƒˆ (Effect Event) とå‘ŧã°ã‚Œã‚‹å†åˆŠį”¨å¯čƒŊãĒé–ĸ数へとæŠŊå‡ēできるようãĢする React フックです。

const onSomething = useEffectEvent(callback)

ãƒĒãƒ•ã‚ĄãƒŦãƒŗã‚š

useEffectEvent(callback)

ã‚ŗãƒŗãƒãƒŧãƒãƒŗãƒˆãŽãƒˆãƒƒãƒ—ãƒŦベãƒĢで useEffectEvent をå‘ŧãŗå‡ēã—ã€ã‚¨ãƒ•ã‚§ã‚¯ãƒˆã‚¤ãƒ™ãƒŗãƒˆã‚’åŽŖč¨€ã—ãžã™ã€‚ã‚¨ãƒ•ã‚§ã‚¯ãƒˆã‚¤ãƒ™ãƒŗãƒˆã¯ã€useEffect ãĒおぎエフェクト内からå‘ŧãŗå‡ēすことができるé–ĸ数です。

import { useEffectEvent, useEffect } from 'react';

function ChatRoom({ roomId, theme }) {
const onConnected = useEffectEvent(() => {
showNotification('Connected!', theme);
});

useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.on('connected', () => {
onConnected();
});
connection.connect();
return () => connection.disconnect();
}, [roomId]);

// ...
}

さらãĢ䞋をčĻ‹ã‚‹

åŧ•æ•°

  • callback: ã‚¨ãƒ•ã‚§ã‚¯ãƒˆã‚¤ãƒ™ãƒŗãƒˆãŽãƒ­ã‚¸ãƒƒã‚¯ã‚’åĢむé–ĸ数。useEffectEvent ã§ã‚¨ãƒ•ã‚§ã‚¯ãƒˆã‚¤ãƒ™ãƒŗãƒˆã‚’åŽšįžŠã™ã‚‹ã¨ã€callback は常ãĢ、å‘ŧãŗå‡ēされたįžŦ間ぎ props や state ぎ最新ぎ値ãĢã‚ĸクã‚ģ゚しぞす。これãĢより、古くãĒãŖãŸã‚¯ãƒ­ãƒŧã‚¸ãƒŖãĢé–ĸã™ã‚‹å•éĄŒã‚’å›žéŋできぞす。

čŋ”り値

ã‚¨ãƒ•ã‚§ã‚¯ãƒˆã‚¤ãƒ™ãƒŗãƒˆé–ĸ数をčŋ”しぞす。こぎé–ĸ数は useEffect、useLayoutEffect、あるいは useInsertionEffect 内でå‘ŧãŗå‡ēすことができぞす。

æŗ¨æ„į‚š

  • エフェクト内でぎãŋå‘ŧãŗå‡ēすīŧšã‚¨ãƒ•ã‚§ã‚¯ãƒˆã‚¤ãƒ™ãƒŗãƒˆã¯ã‚¨ãƒ•ã‚§ã‚¯ãƒˆå†…ã‹ã‚‰ãŽãŋå‘ŧãŗå‡ēすずきです。それをäŊŋį”¨ã™ã‚‹ã‚¨ãƒ•ã‚§ã‚¯ãƒˆãŽį›´å‰ã§åŽšįžŠã™ã‚‹ã‚ˆã†ãĢしãĻください。äģ–ãŽã‚ŗãƒŗãƒãƒŧãƒãƒŗãƒˆã‚„ãƒ•ãƒƒã‚¯ãĢæ¸Ąã•ãĒいでください。eslint-plugin-react-hooks ãƒĒãƒŗã‚ŋīŧˆãƒãƒŧã‚¸ãƒ§ãƒŗ 6.1.1 äģĨ降īŧ‰ã¯ã“ぎåˆļį´„ã‚’åŧˇåˆļすることで、čĒ¤ãŖãŸäŊŋã„æ–šã§ãŽã‚¨ãƒ•ã‚§ã‚¯ãƒˆã‚¤ãƒ™ãƒŗãƒˆãŽå‘ŧãŗå‡ēã—ã‚’é˜˛æ­ĸしぞす。
  • 䞝存配列をéŋけるためぎもぎではãĒいīŧšã‚¨ãƒ•ェクトぎ䞝存配列で䞝存値を指厚することč‡ĒäŊ“ã‚’éŋけるためãĢ useEffectEvent をäŊŋį”¨ã—ãĻはいけぞせん。バグが隠č”Ŋã•ã‚Œã€ã‚ŗãƒŧãƒ‰ãŒį†č§Ŗã—ãĢくくãĒりぞす。明į¤ēįš„ãĢ䞝存値を書くか、åŋ…čρãĢåŋœã˜ãĻ ref をäŊŋį”¨ã—ãĻäģĨ前ぎ値と比čŧƒã™ã‚‹ã‚ˆã†ãĢしãĻください。
  • 非ãƒĒã‚ĸã‚¯ãƒ†ã‚Ŗãƒ–ãĒロジックだけãĢäŊŋうīŧšuseEffectEvent は、値ぎ変化ãĢ䞝存しãĒいロジックをæŠŊå‡ēã™ã‚‹į›Žįš„ãĢぎãŋäŊŋį”¨ã—ãĻください。

äŊŋį”¨æŗ•

最新ぎ props と state をčĒ­ãŋ取る

通常、エフェクト内でãƒĒã‚ĸã‚¯ãƒ†ã‚Ŗãƒ–ãĒ値ãĢã‚ĸクã‚ģ゚する場合は、それを䞝存配列ãĢåĢめるåŋ…čĻãŒã‚ã‚Šãžã™ã€‚ã“ã‚ŒãĢã‚ˆã‚Šã€ããŽå€¤ãŒå¤‰åŒ–ã™ã‚‹ãŸãŗãĢã‚¨ãƒ•ã‚§ã‚¯ãƒˆãŒå†åŽŸčĄŒã•ã‚Œãžã™ã€‚é€šå¸¸ã¯ã“ã‚ŒãŒæœ›ãžã—ã„å‹•äŊœã§ã™ã€‚

しかし場合ãĢã‚ˆãŖãĻは、これらぎ値が変化しãĻã‚‚ã‚¨ãƒ•ã‚§ã‚¯ãƒˆã‚’å†åŽŸčĄŒã•ã›ã‚‹ã“ã¨ãĒく、エフェクト内で最新ぎ props や state をčĒ­ãŋ取りたいことがありぞす。

エフェクト内で最新ぎ props や state をčĒ­ãŋ取る際ãĢ、それらぎ値をãƒĒã‚ĸã‚¯ãƒ†ã‚Ŗãƒ–ãĢしãĒいようãĢするãĢã¯ã€ã‚¨ãƒ•ã‚§ã‚¯ãƒˆã‚¤ãƒ™ãƒŗãƒˆå†…ãĢåĢめぞす。

import { useEffect, useContext, useEffectEvent } from 'react';

function Page({ url }) {
const { items } = useContext(ShoppingCartContext);
const numberOfItems = items.length;

const onNavigate = useEffectEvent((visitedUrl) => {
logVisit(visitedUrl, numberOfItems);
});

useEffect(() => {
onNavigate(url);
}, [url]);

// ...
}

こぎ䞋では、url が変化したあとぎ再ãƒŦãƒŗãƒ€ãƒŧã§ã¯ã‚¨ãƒ•ã‚§ã‚¯ãƒˆãŒå†åŽŸčĄŒã•ã‚Œã‚‹ãšãã§ã™ãŒīŧˆæ–°ã—いペãƒŧジぎč¨Ēå•ã‚’č¨˜éŒ˛ã™ã‚‹ãŸã‚īŧ‰ã€numberOfItems が変化した場合ãĢã¯å†åŽŸčĄŒã•ã‚Œã‚‹ãšãã§ã¯ã‚ã‚Šãžã›ã‚“ã€‚ãƒ­ã‚°č¨˜éŒ˛ãŽãƒ­ã‚¸ãƒƒã‚¯ã‚’ã‚¨ãƒ•ã‚§ã‚¯ãƒˆã‚¤ãƒ™ãƒŗãƒˆã§ãƒŠãƒƒãƒ—ã™ã‚‹ã“ã¨ã§ã€numberOfItems はãƒĒã‚ĸã‚¯ãƒ†ã‚Ŗãƒ–ã§ã¯ãĒくãĒりぞす。エフェクトをトãƒĒã‚ŦすることãĒく、常ãĢ最新ぎ値がčĒ­ãŋ取られぞす。

url ぎようãĒãƒĒã‚ĸã‚¯ãƒ†ã‚Ŗãƒ–ãĒå€¤ã¯ã€ã‚¨ãƒ•ã‚§ã‚¯ãƒˆã‚¤ãƒ™ãƒŗãƒˆãĢåŧ•数としãĻæ¸Ąã™ã“ã¨ã§ã€ãã‚Œã‚‰ã‚’ãƒĒã‚ĸã‚¯ãƒ†ã‚Ŗãƒ–ãĢäŋãĄãĒãŒã‚‰ã€ã‚¤ãƒ™ãƒŗãƒˆå†…ã§æœ€æ–°ãŽéžãƒĒã‚ĸã‚¯ãƒ†ã‚Ŗãƒ–ãĒ値ãĢもã‚ĸクã‚ģ゚することができぞす。