Reactã®experimental_useSubscriptionããã¯ããªã¢ã«ã¿ã€ã ããŒã¿ç®¡çã®å©ç¹ãåçã§ã¬ã¹ãã³ã·ããªã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããããã®å®è·µäŸã解説ããŸãã
React experimental_useSubscriptionã§ãªã¢ã«ã¿ã€ã ããŒã¿ãè§£æŸããïŒå æ¬çã¬ã€ã
é²åãç¶ãããŠã§ãéçºã®äžçã«ãããŠããªã¢ã«ã¿ã€ã ããŒã¿ã¯æãéèŠã§ããæ ªäŸ¡ãã£ãã«ãŒããœãŒã·ã£ã«ã¡ãã£ã¢ã®ãã£ãŒããå
±åç·šéããã¥ã¡ã³ããªã©ãåçãªæ
å ±ã衚瀺ããã¢ããªã±ãŒã·ã§ã³ã«ã¯ãããŒã¿ãã·ãŒã ã¬ã¹ã«ç®¡çã»æŽæ°ããããã®å¹ççãªã¡ã«ããºã ãå¿
èŠã§ããReactã®experimental_useSubscription
ããã¯ã¯ã颿°ã³ã³ããŒãã³ãå
ã§ãªã¢ã«ã¿ã€ã ããŒã¿ã®ãµãã¹ã¯ãªãã·ã§ã³ãåŠçããããã®ã匷åã§æè»ãªãœãªã¥ãŒã·ã§ã³ãæäŸããŸãã
experimental_useSubscription
ãšã¯ïŒ
experimental_useSubscription
ã¯ãæéçµéãšãšãã«æŽæ°ãçºçãããããŒã¿ãœãŒã¹ãžã®ãµãã¹ã¯ã©ã€ãåŠçãç°¡çŽ åããããã«èšèšãããReactããã¯ã§ããããŒãªã³ã°ãæåã®ã€ãã³ããªã¹ããŒã«äŸåããåŸæ¥ã®ããŒã¿ååŸæ¹æ³ãšã¯ç°ãªãããã®ããã¯ã¯ãµãã¹ã¯ãªãã·ã§ã³ã管çããã³ã³ããŒãã³ãã®ç¶æ
ãèªåçã«æŽæ°ããããã®å®£èšçã§å¹ççãªæ¹æ³ãæäŸããŸãã
éèŠäºé
ïŒãã®åã®éããexperimental_useSubscription
ã¯å®éšçãªAPIã§ããããã¯ãå°æ¥ã®ReactãªãªãŒã¹ã§å€æŽãŸãã¯åé€ãããå¯èœæ§ãããããšãæå³ããŸãã倧ããªå©ç¹ãæäŸããŸãããæ¬çªç°å¢ã§æ¡çšããåã«ããã®å®å®æ§ãšå°æ¥ã®å€æŽã®å¯èœæ§ãèæ
®ããŠãã ããã
experimental_useSubscription
ã䜿çšããã¡ãªãã
- 宣èšçãªããŒã¿ç®¡çïŒ å¿ èŠãªããŒã¿ãèšè¿°ããã ãã§ãReactããµãã¹ã¯ãªãã·ã§ã³ãšæŽæ°ãèªåçã«åŠçããŸãã
- æé©åãããããã©ãŒãã³ã¹ïŒ Reactããµãã¹ã¯ãªãã·ã§ã³ãå¹ççã«ç®¡çããäžèŠãªåã¬ã³ããªã³ã°ãæå°éã«æãããããã¢ããªã±ãŒã·ã§ã³ã®ããã©ãŒãã³ã¹ãåäžããŸãã
- ç°¡æœãªã³ãŒãïŒ æåã§ã®ãµãã¹ã¯ãªãã·ã§ã³ç®¡çã«é¢é£ããå®åã³ãŒããåæžããã³ã³ããŒãã³ããããã¯ãªãŒã³ã§ä¿å®ããããããŸãã
- ã·ãŒã ã¬ã¹ãªçµ±åïŒ Reactã®ã³ã³ããŒãã³ãã©ã€ããµã€ã¯ã«ãä»ã®ããã¯ãšã¹ã ãŒãºã«çµ±åããäžè²«æ§ã®ããéçºäœéšãå¯èœã«ããŸãã
- ããžãã¯ã®éçŽïŒ ãµãã¹ã¯ãªãã·ã§ã³ããžãã¯ãåå©çšå¯èœãªããã¯ã«ã«ãã»ã«åããã³ãŒãã®åå©çšæ§ãé«ããéè€ãåæžããŸãã
experimental_useSubscription
ã®ä»çµã¿
experimental_useSubscription
ããã¯ã¯ãåŒæ°ãšããŠsourceãªããžã§ã¯ããšconfigãªããžã§ã¯ããåããŸããsourceãªããžã§ã¯ãã¯ãããŒã¿ãžã®ãµãã¹ã¯ã©ã€ããšååŸã®ããžãã¯ãæäŸããŸããconfigãªããžã§ã¯ãã¯ããµãã¹ã¯ãªãã·ã§ã³ã®åäœãã«ã¹ã¿ãã€ãºã§ããŸããã³ã³ããŒãã³ããããŠã³ãããããšãããã¯ã¯ããŒã¿ãœãŒã¹ã«ãµãã¹ã¯ã©ã€ãããŸããããŒã¿ãœãŒã¹ãæŽæ°ãçºè¡ãããã³ã«ãããã¯ã¯ææ°ã®ããŒã¿ã§ã³ã³ããŒãã³ãã®åã¬ã³ããªã³ã°ãããªã¬ãŒããŸãã
source
ãªããžã§ã¯ã
source
ãªããžã§ã¯ãã¯ã以äžã®ã¡ãœãããå®è£
ããå¿
èŠããããŸãïŒ
read(props)
ïŒ ãã®ã¡ãœããã¯ãæåã«ããŒã¿ãèªã¿èŸŒãããããŸããµãã¹ã¯ãªãã·ã§ã³ãæŽæ°ããããã³ã«åŒã³åºãããŸããããŒã¿ã®çŸåšå€ãè¿ãå¿ èŠããããŸããsubscribe(callback)
ïŒ ãã®ã¡ãœããã¯ãã³ã³ããŒãã³ããããŠã³ããããŠãµãã¹ã¯ãªãã·ã§ã³ã確ç«ããéã«åŒã³åºãããŸããcallback
åŒæ°ã¯ReactãæäŸãã颿°ã§ããããŒã¿ãœãŒã¹ãæ°ããå€ãçºè¡ãããã³ã«ããã®callback
ãåŒã³åºãå¿ èŠããããŸãã
config
ãªããžã§ã¯ãïŒä»»æïŒ
config
ãªããžã§ã¯ãã䜿çšãããšããµãã¹ã¯ãªãã·ã§ã³ã®åäœãã«ã¹ã¿ãã€ãºã§ããŸãã以äžã®ããããã£ãå«ããããšãã§ããŸãïŒ
getSnapshot(source, props)
ïŒ ããŒã¿ã®ã¹ãããã·ã§ãããè¿ã颿°ãã³ã³ã«ã¬ã³ãã¬ã³ããªã³ã°äžã®äžè²«æ§ã確ä¿ããã®ã«åœ¹ç«ã¡ãŸããããã©ã«ãã¯source.read(props)
ã§ããgetServerSnapshot(props)
ïŒ ãµãŒããŒãµã€ãã¬ã³ããªã³ã°äžã«ãµãŒããŒäžã®ããŒã¿ã®ã¹ãããã·ã§ãããè¿ã颿°ãshouldNotify(oldSnapshot, newSnapshot)
ïŒ å€ãã¹ãããã·ã§ãããšæ°ããã¹ãããã·ã§ããã«åºã¥ããŠãã³ã³ããŒãã³ããåã¬ã³ããªã³ã°ãã¹ããã©ãããæ±ºå®ãã颿°ãããã«ãããåã¬ã³ããªã³ã°ã®åäœããã现ããå¶åŸ¡ã§ããŸãã
å®è·µäŸ
äŸ1ïŒãªã¢ã«ã¿ã€ã æ ªäŸ¡ãã£ãã«ãŒ
ãªã¢ã«ã¿ã€ã ã®æ ªäŸ¡ãã£ãã«ãŒã衚瀺ããç°¡åãªã³ã³ããŒãã³ããäœæããŠã¿ãŸããããäžå®ééã§æ ªäŸ¡ãçºçãããããŒã¿ãœãŒã¹ãã·ãã¥ã¬ãŒãããŸãã
ãŸããstockSource
ãå®çŸ©ããŸãããïŒ
const stockSource = {
read(ticker) {
// APIããæ ªäŸ¡ãååŸããã·ãã¥ã¬ãŒã·ã§ã³
return getStockPrice(ticker);
},
subscribe(callback) {
const intervalId = setInterval(() => {
callback(); // Reactã«åã¬ã³ããªã³ã°ãéç¥
}, 1000); // 1ç§ããšã«æŽæ°
return () => clearInterval(intervalId); // ã¢ã³ããŠã³ãæã«ã¯ãªãŒã³ã¢ãã
},
};
// æ ªäŸ¡ååŸãã·ãã¥ã¬ãŒããããããŒé¢æ°
function getStockPrice(ticker) {
// å®éã®ã¢ããªã±ãŒã·ã§ã³ã§ã¯ãå®éã®APIåŒã³åºãã«çœ®ãæããŠãã ãã
const randomPrice = Math.random() * 100;
return { ticker, price: randomPrice.toFixed(2) };
}
次ã«ãexperimental_useSubscription
ã䜿ã£ãŠReactã³ã³ããŒãã³ããäœæããŸãããïŒ
import { unstable_useSubscription as useSubscription } from 'react';
import { useState } from 'react';
function StockTicker() {
const [ticker, setTicker] = useState('AAPL');
const stockData = useSubscription(stockSource, ticker);
return (
{stockData.ticker}: ${stockData.price}
setTicker(e.target.value)}
/>
);
}
export default StockTicker;
ãã®äŸã§ã¯ãStockTicker
ã³ã³ããŒãã³ããstockSource
ã«ãµãã¹ã¯ã©ã€ãããŸããuseSubscription
ããã¯ã¯ãstockSource
ãæ°ããæ ªäŸ¡ãçºè¡ãããã³ã«ã³ã³ããŒãã³ããèªåçã«æŽæ°ããŸããå
¥åãã£ãŒã«ãã§ã¯ããŠãŒã¶ãŒãç£èŠãããã£ãã«ãŒã·ã³ãã«ã倿Žã§ããŸãã
äŸ2ïŒå ±åç·šéããã¥ã¡ã³ããšãã£ã¿
è€æ°ã®ãŠãŒã¶ãŒãåæã«åãããã¥ã¡ã³ããç·šéã§ããå
±åç·šéããã¥ã¡ã³ããšãã£ã¿ãèããŠã¿ãŸããããexperimental_useSubscription
ã䜿çšããŠããã¹ãŠã®ã¯ã©ã€ã¢ã³ãéã§ããã¥ã¡ã³ãã®ã³ã³ãã³ããåæãããããšãã§ããŸãã
ãŸããå
±æããã¥ã¡ã³ããã·ãã¥ã¬ãŒãããç°¡ç¥åãããdocumentSource
ãå®çŸ©ããŸãããïŒ
const documentSource = {
read(documentId) {
// ãµãŒããŒããããã¥ã¡ã³ãã³ã³ãã³ããååŸããã·ãã¥ã¬ãŒã·ã§ã³
return getDocumentContent(documentId);
},
subscribe(callback, documentId) {
// WebSocketæ¥ç¶ãã·ãã¥ã¬ãŒãããŠããã¥ã¡ã³ãã®æŽæ°ãåä¿¡
const websocket = new WebSocket(`ws://example.com/documents/${documentId}`);
websocket.onmessage = (event) => {
// WebSocketæ¥ç¶ãä»ããŠããã¥ã¡ã³ãã®æ°ããããŒãžã§ã³ãåä¿¡ããããšã
callback(); // Reactã«åã¬ã³ããªã³ã°ãéç¥
};
return () => websocket.close(); // ã¢ã³ããŠã³ãæã«ã¯ãªãŒã³ã¢ãã
},
};
// ããã¥ã¡ã³ãã³ã³ãã³ãã®ååŸãã·ãã¥ã¬ãŒããããããŒé¢æ°
function getDocumentContent(documentId) {
// å®éã®ã¢ããªã±ãŒã·ã§ã³ã§ã¯ãå®éã®APIåŒã³åºãã«çœ®ãæããŠãã ãã
return `Document content for document ${documentId} - Version: ${Math.random().toFixed(2)}`;
}
次ã«ãReactã³ã³ããŒãã³ããäœæããŸãããïŒ
import { unstable_useSubscription as useSubscription } from 'react';
function DocumentEditor({ documentId }) {
const documentContent = useSubscription(documentSource, documentId);
return (
);
}
export default DocumentEditor;
ãã®äŸã§ã¯ãDocumentEditor
ã³ã³ããŒãã³ããæäŸãããdocumentId
ã䜿çšããŠdocumentSource
ã«ãµãã¹ã¯ã©ã€ãããŸããã·ãã¥ã¬ãŒããããWebSocketæ¥ç¶ãæŽæ°ãåä¿¡ãããã³ã«ãã³ã³ããŒãã³ãã¯ææ°ã®ããã¥ã¡ã³ãã³ã³ãã³ãã§åã¬ã³ããªã³ã°ãããŸãã
äŸ3ïŒReduxã¹ãã¢ãšã®çµ±å
experimental_useSubscription
ã¯ãReduxã¹ãã¢ã®å€æŽããµãã¹ã¯ã©ã€ãããããã«ã䜿çšã§ããŸããããã«ãããReduxã®ç¶æ
ã®ç¹å®ã®éšåã倿Žããããšãã«ãã³ã³ããŒãã³ããå¹ççã«æŽæ°ã§ããŸãã
user
ã¹ã©ã€ã¹ãæã€Reduxã¹ãã¢ããããšä»®å®ããŸãããïŒ
// Reduxã¹ãã¢ã®èšå®ïŒç°¡ç¥çïŒ
import { createStore } from 'redux';
const initialState = {
user: {
name: 'John Doe',
isLoggedIn: false,
},
};
function reducer(state = initialState, action) {
switch (action.type) {
case 'UPDATE_USER':
return { ...state, user: { ...state.user, ...action.payload } };
default:
return state;
}
}
const store = createStore(reducer);
次ã«ãuser
ã¹ã©ã€ã¹ã®å€æŽããµãã¹ã¯ã©ã€ãããããã®userSource
ãäœæããŸãããïŒ
const userSource = {
read() {
return store.getState().user;
},
subscribe(callback) {
const unsubscribe = store.subscribe(callback);
return unsubscribe;
},
};
æåŸã«ãReactã³ã³ããŒãã³ããäœæããŸãããïŒ
import { unstable_useSubscription as useSubscription } from 'react';
import { useDispatch } from 'react-redux';
function UserProfile() {
const user = useSubscription(userSource);
const dispatch = useDispatch();
return (
Name: {user.name}
Logged In: {user.isLoggedIn ? 'Yes' : 'No'}
);
}
export default UserProfile;
ãã®äŸã§ã¯ãUserProfile
ã³ã³ããŒãã³ããuserSource
ã«ãµãã¹ã¯ã©ã€ãããŸããReduxã¹ãã¢ã®user
ã¹ã©ã€ã¹ã倿Žããããã³ã«ãã³ã³ããŒãã³ãã¯æŽæ°ããããŠãŒã¶ãŒæ
å ±ã§åã¬ã³ããªã³ã°ãããŸãã
é«åºŠãªèæ ®äºé ãšãã¹ããã©ã¯ãã£ã¹
- ãšã©ãŒãã³ããªã³ã°ïŒ
source
ãªããžã§ã¯ãã®read
ã¡ãœããå ã«å ç¢ãªãšã©ãŒãã³ããªã³ã°ãå®è£ ããããŒã¿ååŸäžã«çºçããå¯èœæ§ã®ãããšã©ãŒãé©åã«åŠçããŸãã - ããã©ãŒãã³ã¹ã®æé©åïŒ
config
ãªããžã§ã¯ãã®shouldNotify
ãªãã·ã§ã³ã䜿çšããŠãããŒã¿ãå®éã«å€æŽãããŠããªãå Žåã®äžèŠãªåã¬ã³ããªã³ã°ãé²ããŸããããã¯ãè€éãªããŒã¿æ§é ã«ãšã£ãŠç¹ã«éèŠã§ãã - ãµãŒããŒãµã€ãã¬ã³ããªã³ã°ïŒSSRïŒïŒ
config
ãªããžã§ã¯ãã«getServerSnapshot
ã®å®è£ ãæäŸããSSRäžã«åæããŒã¿ããµãŒããŒã§å©çšå¯èœã§ããããšãä¿èšŒããŸãã - ããŒã¿å€æïŒ
read
ã¡ãœããå ã§ããŒã¿å€æãè¡ããã³ã³ããŒãã³ãã§äœ¿çšãããåã«ããŒã¿ãæ£ãã圢åŒã«ãªã£ãŠããããšã確èªããŸãã - ãªãœãŒã¹ã®ã¯ãªãŒã³ã¢ããïŒ ã¡ã¢ãªãªãŒã¯ãé²ãããã«ã
subscribe
ã¡ãœããã®ã¯ãªãŒã³ã¢ãã颿°ã§ããŒã¿ãœãŒã¹ããé©åã«ã¢ã³ãµãã¹ã¯ã©ã€ãããããã«ããŠãã ããã
ã°ããŒãã«ãªèæ ®äºé
ã°ããŒãã«ãªãŠãŒã¶ãŒåãã«ãªã¢ã«ã¿ã€ã ããŒã¿ã䜿çšããã¢ããªã±ãŒã·ã§ã³ãéçºããéã¯ã以äžãèæ ®ããŠãã ããïŒ
- ã¿ã€ã ãŸãŒã³ïŒ æéã«ææãªããŒã¿ã衚瀺ããéã¯ãã¿ã€ã ãŸãŒã³ã®å€æãé©åã«åŠçããŸããäŸãã°ãæ ªäŸ¡ãã£ãã«ãŒã¯ãŠãŒã¶ãŒã®ããŒã«ã«ã¿ã€ã ãŸãŒã³ã§äŸ¡æ Œã衚瀺ãã¹ãã§ãã
- é貚æç®ïŒ éèããŒã¿ã衚瀺ããéã«é貚æç®ãªãã·ã§ã³ãæäŸããŸããä¿¡é Œã§ããé貚æç®APIã䜿çšããŠããªã¢ã«ã¿ã€ã ã®çºæ¿ã¬ãŒããååŸããããšãæ€èšããŠãã ããã
- ããŒã«ãªãŒãŒã·ã§ã³ïŒ ãŠãŒã¶ãŒã®ãã±ãŒã«ã«å¿ããŠãæ¥ä»ãšæ°å€ã®åœ¢åŒãããŒã«ã©ã€ãºããŸãã
- ãããã¯ãŒã¯é å»¶ïŒ ç¹ã«ã€ã³ã¿ãŒãããæ¥ç¶ãé ãå°åã®ãŠãŒã¶ãŒã®ããã«ãæœåšçãªãããã¯ãŒã¯é å»¶ã®åé¡ã«æ³šæããŠãã ããããªããã£ãã¹ãã£ãã¯æŽæ°ããã£ãã·ã³ã°ãªã©ã®æè¡ãå®è£ ããŠããŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ãåäžãããŸãã
- ããŒã¿ãã©ã€ãã·ãŒïŒ ãŠãŒã¶ãŒããŒã¿ãæ±ãéã¯ãGDPRãCCPAãªã©ã®ããŒã¿ãã©ã€ãã·ãŒèŠå¶ãéµå®ããããã«ããŠãã ããã
experimental_useSubscription
ã®ä»£æ¿ææ®µ
experimental_useSubscription
ã¯ãªã¢ã«ã¿ã€ã ããŒã¿ã管çãã䟿å©ãªæ¹æ³ãæäŸããŸãããããã€ãã®ä»£æ¿ã¢ãããŒããååšããŸãïŒ
- Context APIïŒ Context APIã¯è€æ°ã®ã³ã³ããŒãã³ãéã§ããŒã¿ãå
±æããããã«äœ¿çšã§ããŸããããããé »ç¹ãªæŽæ°ã管çããç¹ã§ã¯
experimental_useSubscription
ã»ã©å¹ççã§ã¯ãªããããããŸããã - Reduxããã®ä»ã®ç¶æ 管çã©ã€ãã©ãªïŒ Reduxããã®ä»ã®ç¶æ 管çã©ã€ãã©ãªã¯ãã¢ããªã±ãŒã·ã§ã³ã®ç¶æ ã管çããããã®äžå€®éæš©çãªã¹ãã¢ãæäŸããŸãããªã¢ã«ã¿ã€ã ããŒã¿ã®åŠçã«äœ¿çšã§ããŸããã远å ã®è€éããããããå¯èœæ§ããããŸãã
- ã€ãã³ããªã¹ããŒãæã€ã«ã¹ã¿ã ããã¯ïŒ ã€ãã³ããªã¹ããŒã䜿çšããŠããŒã¿ãœãŒã¹ã«ãµãã¹ã¯ã©ã€ãããã«ã¹ã¿ã ããã¯ãäœæã§ããŸãããã®ã¢ãããŒãã¯ãµãã¹ã¯ãªãã·ã§ã³ããã»ã¹ã«å¯Ÿããããå€ãã®å¶åŸ¡ãæäŸããŸãããããå€ãã®å®åã³ãŒããå¿ èŠã§ãã
çµè«
experimental_useSubscription
ã¯ãReactã¢ããªã±ãŒã·ã§ã³ã§ãªã¢ã«ã¿ã€ã ããŒã¿ã®ãµãã¹ã¯ãªãã·ã§ã³ã管çããããã®åŒ·åã§å¹ççãªæ¹æ³ãæäŸããŸãããã®å®£èšçãªæ§è³ªãæé©åãããããã©ãŒãã³ã¹ããããŠReactã®ã³ã³ããŒãã³ãã©ã€ããµã€ã¯ã«ãšã®ã·ãŒã ã¬ã¹ãªçµ±åã¯ãåçã§ã¬ã¹ãã³ã·ããªãŠãŒã¶ãŒã€ã³ã¿ãŒãã§ãŒã¹ãæ§ç¯ããããã®è²ŽéãªããŒã«ã§ããããããããã¯å®éšçãªAPIã§ããããšãå¿ããã«ãæ¬çªç°å¢ã§æ¡çšããåã«ã¯ãã®å®å®æ§ãæ
éã«æ€èšããŠãã ããã
ãã®ã¬ã€ãã§æŠèª¬ãããååãšãã¹ããã©ã¯ãã£ã¹ãçè§£ããããšã§ãexperimental_useSubscription
ãæŽ»çšããŠReactã¢ããªã±ãŒã·ã§ã³ã«ããããªã¢ã«ã¿ã€ã ããŒã¿ã®å¯èœæ§ãæå€§éã«åŒãåºããäžçäžã®ãŠãŒã¶ãŒã«é
åçã§æçãªäœéšãåµé ããããšãã§ããŸãã
ãããªãæ¢æ±
- Reactããã¥ã¡ã³ããŒã·ã§ã³ïŒ
experimental_useSubscription
ã«é¢ããæŽæ°æ å ±ã«ã€ããŠã¯ãå ¬åŒã®Reactããã¥ã¡ã³ããŒã·ã§ã³ã«æ³šç®ããŠãã ããã - ã³ãã¥ããã£ãã©ãŒã©ã ïŒ ãã©ãŒã©ã ããã£ã¹ã«ãã·ã§ã³ããŒãã§Reactã³ãã¥ããã£ãšäº€æµããä»ã®éçºè ãã¡ã®ãã®ããã¯ã«é¢ããçµéšããåŠã³ãŸãããã
- å®éšïŒ æåã®åŠç¿æ¹æ³ã¯å®è·µããããšã§ããèªèº«ã®ãããžã§ã¯ãã§
experimental_useSubscription
ã詊ããŠããã®èœåãšéçã«ã€ããŠã®çè§£ãæ·±ããŸãããã