ReactããŒãžã§ã³ïŒ
16.13.0
çé¢ç®ã§ãç§ãåããŠããããžãã¹ã¯ããã«å šãèå³ããããŸããã æããã«ãç§ã以åã«èŠåãåãåã£ããšããŠãããã®ãããªèŠåã衚瀺ãããããšã¯æ±ºããŠãããŸããã§ããã çŸåšããšã©ãŒãä¿®æ£ããã®ã¯éåžžã«å°é£ã§ããããã¯ãããŸããŸãªã±ãŒã¹ã§çºçããã¹ã¿ãã¯ãã¬ãŒã¹ãèšå€§ã«ãªãããã§ãã 衚瀺ããããšã©ãŒã®å°ãªããšã1ã€ãä¿®æ£ããããšããŸãããããã§ã«å€ãã®æéãããããŸããã 䜿çšæžã¿ã©ã€ãã©ãªã®ããã€ãããããã°ããããšããŸããããããŸããããŸããã§ããã
ã»ãã®äžäŸïŒ
ããã§ãå€ãreact-routerãå€ãredux-connectïŒå€ãcomponentWillReceiveProps
ã¡ãœããã®ãšã©ãŒãä¿®æ£ããããã«ãããžã§ã¯ããœãŒã¹ã«é
眮ããå¿
èŠããããŸããïŒãrecomposeã«ãã£ãŠäœæãããããã€ãã®HOCãªã©ã®äœ¿çšã«æ°ä»ãããšãã§ããŸããã¯ãç§ãéçºããã³ã³ããŒãã³ãããŠã©ãŒã¯ã¹ã«ãŒãã setState
æååã§æ€çŽ¢ããŠãã°ãä¿®æ£ã§ãããåçŽãªä»®æ³DOMããªãŒã§ã¯ãããŸãããããã¯ããããããã¯ããã«è€éã§ãã
ãã®ãšã©ãŒãç¡å¹ã«ãããããšã©ãŒãã¹ããŒãããå ŽæãèŠã€ããããã®ããç°¡åãªæ¹æ³ãæäŸããã«ã¯ããUNSAFEããªãã·ã§ã³ãäœæããŠãã ããð
ãã®èŠåã以åã«è¿œå ããŠããã°ããã£ãã®ã«ã ç³ãèš³ãããŸããã ããã¯ã®å°å ¥ã«ããèŠèœãšãã§ããã ããã¯ãããã¯ã䜿çšããæ°ããã³ãŒããåå ã§ãããšèããããŸããããã¯ãã¯ãã以åã«ã¯ã©ã¹ã«å¯ŸããŠåãèŠåããã§ã«çºçããŠããããã以åã®ã³ãŒãã§ã¯ãã§ã«ãã®èŠåã衚瀺ãããŠããããã§ãã
ããã¯ãReactã®å°æ¥ã®ããŒãžã§ã³ã§ããŒããã§ã€ã«ãéå§ããå¯èœæ§ãé«ãããšã«æ³šæããŠãã ããã æå³çãŸãã¯ãã®ä»ïŒãã®ãã¿ãŒã³ã«ã¯å€ãã®ãã°ããããŸãïŒã ãããã£ãŠãããã«ãããããããå€ãããŒãžã§ã³ã§ç«ã¡åŸçããŠããŸãå¯èœæ§ããããŸãã ä¿®æ£ã§ããªãå Žåã¯ãå€ãããŒãžã§ã³ã®Reactã«åºå®ããããšããå§ãããŸãã
ãã ããããã¯èšã£ãŠããã©ã€ãã©ãªã®äœæè ããä¿®æ£ããŒãžã§ã³ãå ¬éããããã®æ¯æŽãåŸãããšãã§ãããã©ããã確èªãããªã©ããããã®ä¿®æ£ãã§ããéãç°¡åã«è¡ããããã«æ¯æŽããããšèããŠããŸãã
Chromeã³ã³ãœãŒã«ã§å°ããª>
ç¢å°ãå±éãããšãïŒã¹ã¯ãªãŒã³ã·ã§ããã®ã³ã³ããŒãã³ãã¹ã¿ãã¯ã«å ããŠïŒè¿œå ã®ã¹ã¿ãã¯ãã¬ãŒã¹ã衚瀺ãããŸãã ããªãããããæçš¿ã§ããŸããïŒ ããã«ãããã¬ã³ããªã³ã°ã§å¯äœçšãåŒãèµ·ãããŠããæ£ç¢ºãªã³ãŒã«ãµã€ãã衚瀺ãããŸãã
ç§ãšäžç·ã«ããã¯ç§ãformikã䜿ããšãã«çŸããŸã
@sebmarkbageã
ããã«è²Œãä»ããããããŒã¹ããã³ãžã®ãªã³ã¯ãäžããã€ããã§ããããå¥ã®æ¹åãè©ŠããŸããã ããã€ãã®äœ¿çšæžã¿ã©ã€ãã©ãªã®Githubã®åé¡ã調ã¹ããšããã容çè ã®1人ãredux-formã§ããããšãããããŸããïŒ https ïŒ
ããããããã§ããç§ã¯ãã®åé¡ãéããªãããã«ãé¡ãããããšæããŸããä»ã®éçºè ã«ããããã®ãšã©ãŒã®åå ãšãªãã©ã€ãã©ãªã«ã€ããŠããã§èšåããããšãææ¡ããŸãã
@RodolfoSilvaããã¯formikã«ãã£ãŠåŒãèµ·ããããŠãããšç¢ºä¿¡ããŠããŸããïŒ ã¯ãã®å Žåãããã§åé¡ãäœæããããã«ãªã³ã¯ãæçš¿ããŠããã ããŸããïŒ ãªã¹ãã«è€æ°ã®é ç®ãå«ãŸããå Žåã¯ãæåã®ã¡ãã»ãŒãžã®åé ã§ãã®ãããªåé¡ã®ãªã¹ããäœæããŸãã
ããã¯æ¬åœã«ã§ããã ãæ©ã察åŠããå¿ èŠããããŸãã ã¢ããã°ã¬ãŒããäžå¯èœã«ãªããŸãã ãšã©ãŒãã¬ãŒã¹ã¯ã»ãšãã©äžå¯èœã§ãã
ããŒãã ãšã©ãŒã¡ãã»ãŒãžã§ã©ã®è¡ãæ¢ãã¹ããã説æããããšã圹ç«ã€ãã©ããçåã«æããŸãã
ãã®å Žåãæåã«æ€çŽ¢ããè¡ã¯dispatchAction
åŸã®è¡ã§ãã ãããReactãåŒã³åºããã®ã§ãªããã°ãªããŸããã
@RodolfoSilvaå
±æã§ãããã®ã§ããã°ã FormItemInput.js
ã®ãœãŒã¹ãæçš¿ã§ããŸããïŒ 71è¡ç®ã§dispatchãŸãã¯setStateãåŒã³åºããŠããããã§ãã
ãã®ãšã©ãŒã¡ãã»ãŒãžãå€æŽããŠããšã©ãŒã®åå ãšãªã£ãŠããã³ãŒãè¡ãæ£ç¢ºã«å«ããããšãäžå¯æ¬ ã ãšæããŸãã åé¡ã®åå ãããŒã«ã«ã³ãŒããªã®ãã©ã€ãã©ãªã³ãŒããªã®ããç¹å®ããããšã¯ã»ãšãã©äžå¯èœã§ãã react-reduxãreact-routerãªã©ã®å€éšå¯èœæ§ãéåžžã«é«ãã§ããããããç°¡åã«ç¹å®ããããšã¯äžå¯èœã§ãã
React-Reduxã«åé¡ã¯ãªããšç¢ºä¿¡ããŠããŸããããšã©ãŒã¡ãã»ãŒãžãšã³ã³ããŒãã³ãã¹ã¿ãã¯ã«ãããå®éã«äœãèµ·ãã£ãŠããã®ããç¥ãã®ãé£ããããšã«åæããŸããã
Redux-formã§ãåãåé¡ã«çŽé¢ããŠããŸãïŒ
ç§ã¯åãåé¡ãæ±ããŠããã reduxãã£ãŒã«ãã«åããŠæžã蟌ãã ãšãããŸãã¯ãã¹ãŠã¯ãªã¢ãããšãã«èŠåã衚瀺ãããŠããã®ã
ç§ããã®åé¡ãæ±ããŠããŸããããã¯ç§ã®ã³ã³ããŒãã³ãã§ãïŒ
`const [priceãsetPrice] = useStateïŒ0ïŒ;
const updatePrice =ïŒnewPriceïŒ=> {
setPriceïŒnewPriceïŒ
}
<CardContainer onPriceUpdated = {updatePrice}> CardContainer>
`
ãããã£ãŠããã®å Žåãç§ã®CardContainerã³ã³ããŒãã³ãã¯ãäŸ¡æ ŒãæŽæ°ããã芪ã³ã³ããŒãã³ããæ°ããçåãã¬ã³ããªã³ã°ãããšãã«ã芪ã³ã³ããŒãã³ãã«éç¥ããŸãã
ãããã£ãŠãReactã¯ãä»ã®ã³ã³ããŒãã³ãã®æ©èœã䜿çšããŠã³ã³ããŒãã³ãã®ç¶æ
ãæŽæ°ããããšããŠããããšãèŠåããŠãããšæããŸãã
ç§ã¯reactãåããŠãªã®ã§ããããReactãã¿ãŒã³ãªã®ãããããšãå®éã«ã¯ãã°ãªã®ãããããŸããã
ãã®èŠåã解決ããããã®ææ¡ãããã°ãç§ã¯ãããããã ããã°å¹žãã§ãã
@ l0gicgate
ãã®ãšã©ãŒã¡ãã»ãŒãžãå€æŽããŠããšã©ãŒã®åå ãšãªã£ãŠããã³ãŒãè¡ãæ£ç¢ºã«å«ããããšãäžå¯æ¬ ã ãšæããŸãã
JavaScriptã§ã§ããããšã«ã¯éçããããŸãã ãã ãããã¹ãŠã®æ å ±ã¯ãã©ãŠã¶ã«è¡šç€ºãããã¹ã¿ãã¯ã«ãããŸãã ããªããããå¿ èŠãããã®ã¯ãReactã®äžã«ããè¡ãã¹ãããããããšã§ãã
JavaScriptã¹ã¿ãã¯ã衚瀺ããã«ã¯ããšã©ãŒã¡ãã»ãŒãžã®æšªã«ããå°ããªç¢å°ããŸãã
ããšãã°ãåã®ã¹ã¯ãªãŒã³ã·ã§ãããèŠãŠãã ããã
ã¹ã¿ãã¯ãæãäžããã®ã¯å°ãé¢åã§ãããæåã®æ°ãã¬ãŒã ãã¹ãããããã®ã¯ããã»ã©é£ããããšã§ã¯ãããŸããã 次ã®ãã¬ãŒã ãåé¡ã®åå ã§ãã ãã®å ŽåãFormikã©ã€ãã©ãªå ã®äœãã®ããã«èŠããŸãã ã ããããªãã¯ããã§åé¡ãæåºããããšãã§ããŸãã
@martinezwilmerãã®äŸã¯å°ããããŠåœ¹ã«ç«ã¡ãŸããã ãµã³ãããã¯ã¹ãäœæããŠãã ããã
å°æ¥ã®ã³ã¡ã³ããŒã¿ãŒãžã æ°ããèŠåãèŠãã®ã¯ã€ã©ã€ã©ããããšãç解ããŠããŸãã ããããããã¯ããªãã®ã³ãŒãã«ãã°ãåŒãèµ·ãããŠãŠããŸãã ç®èãç ©ãããã®è¡šçŸããé æ ®ããã ããã°å¹žãã§ãã
ã¹ã¿ãã¯ãã¬ãŒã¹ã®ã©ãããæ¥ãŠããã®ãããããªãå Žåã¯ãã¹ã¯ãªãŒã³ã·ã§ãããæçš¿ããããåçŸãµã³ãããã¯ã¹ãäœæããŠãã ããããµããŒããããŠããã ããŸãã ãããã®ã»ãšãã©ã¯ããããããã€ãã®ã©ã€ãã©ãªããã®ãã®ã§ãããããæãçç£çãªæ¹æ³ã¯ããããã®ã±ãŒã¹ãæžãããŠããããããã®ã©ã€ãã©ãªã§åé¡ãå ±åããããšã§ãã
çãããããããšãããããŸããã
ããã§ã®èŠåã«é¢ä¿ããæ£ç¢ºãªç·ãèŠã€ããã®ã¯é£ããã§ãïŒ
@gaearonããäžåºŠãããã«ã€ããŠ1ã€ã®ãã³ãããããŸããïŒ
ããã§ã®èŠåã«é¢ä¿ããæ£ç¢ºãªç·ãèŠã€ããã®ã¯é£ããã§ãïŒ
äœãé£ããã®ã§ããïŒ äžã§è¿°ã¹ãããã«ãããã¯å³åŽã«ãåå¿ããããšæžãããŠããªãæåã®è¡ã§ãã ãã®å ŽåãReduxããã®connectAdvanced
ã§ãã ã¡ã³ããããããèŠãæ©äŒãããããã«ãReactReduxã«åé¡ãæåºããŠãã ããã
ã¢ããã¹ã¬ããã§èšã£ãããã«ãããã§èµ·ãã£ãŠããããšãReact-Reduxã®åé¡ã§ãããšããããç§ã¯_éåžžã«_é©ããŸãã
ãšã¯èšããã®ã®ãããããäœããã®ã¡ãã»ãŒãžãããªã¬ãŒããã®ãæ£ç¢ºã«ã¯ããããŸããã ãšã©ãŒã¡ãã»ãŒãžã®å 容ãååç解ããŸããããå®éã«ã¯ã©ã®ãããªã¢ããªã³ãŒããã¿ãŒã³ããã®åäœã®äŸã«ãªãã§ããããïŒ
ç§ã¯æè¿ããã«ééããä¿®æ£ã¯setState
ãã³ãã©ãŒåŒã³åºããµã€ããuseEffect
ã§ã©ããããŠããŸããïŒ https ïŒ onChange
ãšonSubmit
ã¯ããã§ãŒã³ã®äžäœã«ããsetState
䜿çšããŸãïŒã
@martinezwilmer onPriceUpdated
ã¯ã©ãã§åŒã³åºãããŠããŸããïŒ ãã¶ããããuseEffect
å
ãã§ã¿ãŠãã ããïŒ
åãåé¡ãurql
use-subscription
+ wonkaïŒã¹ããªãŒã çšïŒã䜿çšããŠæŽæ°ã調æŽããŠããŸãããæŽæ°ã¯åæããŠè¡ãããå¯èœæ§ããããŸãã ããã§ã¯ãã§ã«todos
ãã§ããããŠããã®ã§ã Open
ãã¿ã³ãã¯ãªãã¯ãããšãçµæãããã«ãããã¢ããããã¯ãã§ãããããã«ãã次ã®ãšã©ãŒãçºçããããã§ãã
ç§ãã¡ã®å Žåãããã¯æå³ããããã®ã§ãããåæçµæã«å¯ŸããŠfetching: true
ã ãã衚瀺ããããšã¯ã§ããŸããããã®çµæãã€ã³ã¿ãŒãã§ã€ã¹ããžã£ã³ãããŸãã
ããã¯çŸåšããµãŒãããŒãã£ã®ã©ã€ãã©ãªã§ãŸããŸãå¢ãå§ããŠããŸãïŒ urql
ã Apollo ã
ç§ã¯ããã«ééããæ°æéã®éãåé¡ã¯ç§ã®ã³ãŒãã«ãããšæããŸããã å§çž®ãããã¹ã¿ãã¯ãã¬ãŒã¹ã¯ã³ã³ããŒãã³ããæããŠããŸããæ瀺çã«ãšã©ãŒãããªã¬ãŒãããšãã«ãå±éãããã¹ã¿ãã¯ãã¬ãŒã¹ã«ãµãŒãããŒãã£ã®ã©ã€ãã©ãªã衚瀺ãããããšã¯çãããããŸããã ãã®ç¹å®ã®èŠåã«é¢ããç§ã®ïŒéå®çã§ã¯ãããŸããïŒèª¿æ»ãããã»ãšãã©ã®éçºè ããã®åé¡ãèªåã§åŒãèµ·ãããŠããã®ã§ã¯ãªããçºçããŠããã³ãŒãã«äŸåããŠããããã§ãã éåžžãã¢ããã¹ããªãŒã ã®ãã°ã§ã¯ãªããšæ³å®ããããšããå§ãããŸãããã¢ããã¹ããªãŒã ã®ãã°ã§ããå Žåãååšããªãã³ãŒãã®åé¡ã远跡ããããã«æéã浪費ããããšã¯ããªãèç«ãããããšã§ãã å¹³åçãªãŠãŒã¶ãŒãèªåãæžããã³ãŒããªã®ãããããšãäŸåããŠããã³ãŒããåé¡ã®åå ãªã®ããå€æããã®ã«åœ¹ç«ã€Reactã§ã§ããããšã¯ãããŸããïŒ
ã¢ããã®åé¡ããç§ã泚æããããšã®1ã€ã¯æ¬¡ã®ãšããã§ãã
èŠåã®ã¹ã¿ãã¯ãã¬ãŒã¹ã¯ãå€æŽãåæåããã³ã³ããŒãã³ãã瀺ããŠããããããã®å€æŽã«ãã£ãŠ[åæã®ãŸãŸ]åã¬ã³ããªã³ã°ãããã³ã³ããŒãã³ãã§ã¯ãããŸããã
ãããæ£ãããã°ãReactã¯ããã§ããå€ãã®æ å ±ãæäŸã§ããŸããïŒ ãããããéå§ã³ã³ããŒãã³ããšãããæŽæ°ãããã³ã³ããŒãã³ãã®äž¡æ¹ãæããŠãããŸããïŒ
@hugoã®ããã«ãæ°ããIonicã¢ããªã±ãŒã·ã§ã³ããã¹ã
npx ionic start demo sidemenu --type=react
react-scripts test
å®éãåå ã¯ã¹ã¿ãã¯ãã¬ãŒã¹ã®äžå€®ãšäžéšã«åãããŠããŸãã
console.error node_modules/react-dom/cjs/react-dom.development.js:88
Warning: Cannot update a component from inside the function body of a different component.
in Route (at App.tsx:37)
in View (created by StackManagerInner)
in ViewTransitionManager (created by StackManagerInner)
in ion-router-outlet (created by IonRouterOutlet)
in IonRouterOutlet (created by ForwardRef(IonRouterOutlet))
in ForwardRef(IonRouterOutlet) (created by StackManagerInner)
in StackManagerInner (created by Context.Consumer)
in Unknown (created by Component)
in Component (created by ForwardRef(IonRouterOutlet))
in ForwardRef(IonRouterOutlet) (at App.tsx:36)
in ion-split-pane (created by IonSplitPane)
in IonSplitPane (created by ForwardRef(IonSplitPane))
in ForwardRef(IonSplitPane) (at App.tsx:34)
in NavManager (created by RouteManager)
in RouteManager (created by Context.Consumer)
in RouteManager (created by IonReactRouter)
in Router (created by BrowserRouter)
in BrowserRouter (created by IonReactRouter)
in IonReactRouter (at App.tsx:33)
in ion-app (created by IonApp)
in IonApp (created by ForwardRef(IonApp))
in ForwardRef(IonApp) (at App.tsx:32)
in App (at App.test.tsx:6)
ãã®åé¡ã¯ããã®åé¡ã«é¢ããŠç§ãèŠã€ããæãè¿ãåé¡ã§ããã
https://github.com/mobxjs/mobx-react/issues/846ã§ãmobxã§ãã®åé¡ãåŒãèµ·ããç¹å®ã®ãã¿ãŒã³ãèŠã€ããŸãã
@sebmarkbageãã®åé¡ãåçŸã§ããªããªããŸããã ããã€ãã®ã©ã€ãã©ãªãšåé¡ãæŽæ°ããŸããã
@jgouxåãåé¡ã«çŽé¢ããŠããããã§ã@ Clovis ^^çºèŠ
æŽæ°ãreact 16.13.0
åå¿ããåŸããã®ãšã©ãŒãçºçãå§ããŸããã ç¹å®ã®ã¢ã¯ã·ã§ã³ãå®è¡ãããåŸãã³ã³ããŒãã³ãã®1ã€ãå¥ã®ã³ã³ããŒãã³ããæŽæ°ããŠãããããåé¡ã¯ããªãæ確ã§ãã ãã ãããªããããèŠåãã¹ããŒããã®ãããããŸããã ãããåé¿ããæ¹æ³ã«ã€ããŠäœãææ¡ã¯ãããŸããïŒ
@gaearonã¹ã¿ãã¯ãããããã°ããæ¹æ³ã®è©³çŽ°ã«æè¬ããŸãããã®äŸã瀺ããªãã£ãå Žåãç§ã¯å人çã«ãã®ãšã©ãŒãã©ãããæ¥ãã®ããç解ã§ããªãã£ãã§ãããã ð
åé¡ãé¢é£ããŠãããã©ããã¯ããããŸãããããã©ãŒã ã³ã³ããŒãã³ãã®ç¶æ ãæŽæ°ããããšããŠããŸãããonChangeãã³ãã©ãŒãè¿œå ããããšãããšããã®ãšã©ãŒãçºçãç¶ããŸãã 念ã®ããã«èšã£ãŠãããŸãããç§ã¯react-jsonschema-formã䜿çšããŠFormã³ã³ããŒãã³ããã€ã³ããŒããããã®onChangeããããã£ã䜿çšããŠç¶æ ãæŽæ°ããŠããŸãã
ç§ã«ãšã£ãŠããããåé¡ã®åå ãšãªããã¿ãŒã³ã§ãã
ãããåé¿ããæ¹æ³ããããããããŸããã ããããã³ã³ãœãŒã«ãã°ã¯ç§ã385è¡ç®ã«ãŸã£ããã«åããŸãã
ç§ã¯åå¿ããã®ã¯åããŠã§ããã次ã®ãããªã³ãŒãããããŸããïŒ
import React, { useState } from "react";
function Home() {
const [mobileNavOpen, setMobileNavOpen] = useState(false);
return (
<div>
<button
onClick={(): void => setMobileNavOpen(true)}
type="button"
className="btn"
>
X
</button>
{mobileNavOpen && <MobileNav setMobileNavOpen={setMobileNavOpen}/>}
</div>
);
}
function MobileNav() {
return (
<div>
<button
onClick={setMobileNavOpen(false)} //problem here
type="button"
className="btn"
>
X
</button>
</div>
);
}
export default Home;
ãã®çµæïŒ Cannot update a component from inside the function body of a different component.
ç§ãããªããã°ãªããªãã£ãã®ã¯ã次ã®ããã«MobileNavã®setMobileNavOpenã«ç¢å°é¢æ°ãè¿œå ããããšã§ãã
import React, { useState } from "react";
function Home() {
const [mobileNavOpen, setMobileNavOpen] = useState(false);
return (
<div>
<button
onClick={(): void => setMobileNavOpen(true)}
type="button"
className="btn"
>
X
</button>
{mobileNavOpen && <MobileNav setMobileNavOpen={setMobileNavOpen}/>}
</div>
);
}
function MobileNav() {
return (
<div>
<button
onClick={(): void => setMobileNavOpen(false)} //fixes problem
type="button"
className="btn"
>
X
</button>
</div>
);
}
export default Home;
ãããŠããã¯åé¡ã解決ããŸããããã誰ããå©ããããšãé¡ã£ãŠããŸãïŒ
ç§ã¯åå¿ããã®ã¯åããŠã§ããã次ã®ãããªã³ãŒãããããŸããïŒ
import React, { useState } from "react"; function Home() { const [mobileNavOpen, setMobileNavOpen] = useState(false); return ( <div> <button onClick={(): void => setMobileNavOpen(true)} type="button" className="btn" > X </button> {mobileNavOpen && <MobileNav setMobileNavOpen={setMobileNavOpen}/>} </div> ); } function MobileNav() { return ( <div> <button onClick={setMobileNavOpen(false)} //problem here type="button" className="btn" > X </button> </div> ); } export default Home;
ãã®çµæïŒ
Cannot update a component from inside the function body of a different component.
ç§ãããªããã°ãªããªãã£ãã®ã¯ã次ã®ããã«MobileNavã®setMobileNavOpenã«ç¢å°é¢æ°ãè¿œå ããããšã§ãã
import React, { useState } from "react"; function Home() { const [mobileNavOpen, setMobileNavOpen] = useState(false); return ( <div> <button onClick={(): void => setMobileNavOpen(true)} type="button" className="btn" > X </button> {mobileNavOpen && <MobileNav setMobileNavOpen={setMobileNavOpen}/>} </div> ); } function MobileNav() { return ( <div> <button onClick={(): void => setMobileNavOpen(false)} //fixes problem type="button" className="btn" > X </button> </div> ); } export default Home;
ãããŠããã¯åé¡ã解決ããŸããããã誰ããå©ããããšãé¡ã£ãŠããŸãïŒ
ããªãã®äŸã¯ãå®éã«ã¯äººã
ãåå¿ããããšã§ç¯ãåæã®éã¡ã®1ã€ã§ãã ããã§è°è«ãããŠããã®ãšãŸã£ããåãåé¡ãã©ããã¯ããããŸããã ããã§ã®ããªãã®è¡ïŒ onClick={setMobileNavOpen(false)
ã¯ãã¯ãªãã¯ã§ã¯ãªãããã¿ã³ã®å
¥æäžã«é¢æ°ãåŒã³åºããŠããŸãã ãã®ãããç¢å°é¢æ°ã§ã©ãããããšä¿®æ£ãããŸãã
React Routerã§ãã®åé¡ãçºçãããŠãŒã¶ãŒãå¥ã®å Žæã«<Redirect>
ããåã«ãReduxã¢ã¯ã·ã§ã³ããã£ã¹ãããããå¿
èŠããããŸããã åé¡ã¯ããã£ã¹ããããå®äºããåã«ãªãã€ã¬ã¯ããçºçããããšã§ããããã«æãããŸããã ç§ã¯èªåã®è¡åãçŽæããããšã§åé¡ã解決ããŸããã
åïŒ
<Route
render={routeProps => {
setRedirectionTarget(somePath(routeProps));
return <Redirect to={someOtherPath} />;
}}
/>;
function mapDispatchToProps(dispatch: ThunkDispatch) {
return {
setRedirectionTarget: (target: string | null) => dispatch(setRedirectionTarget(target))
};
}
export const setRedirectionTarget = (location: string | null): SetRedirectionTarget => {
return {
type: SET_REDIRECTION_TARGET,
location
};
};
åŸïŒ
function mapDispatchToProps(dispatch: ThunkDispatch) {
return {
setRedirectionTarget: async (target: string | null) => dispatch(await setRedirectionTarget(target))
};
}
export const setRedirectionTarget = (location: string | null): Promise<SetRedirectionTarget> => {
return Promise.resolve({
type: SET_REDIRECTION_TARGET,
location
});
};
ãšã©ãŒã¡ãã»ãŒãžã«ãçŸåšã¬ã³ããªã³ã°ããŠããã³ã³ããŒãã³ããšãsetStateãåŒã³åºãããŠããã³ã³ããŒãã³ãã®äž¡æ¹ã®ååãå«ãããšãããšæããŸãã 誰ããããã®ããã«PRãéãããã§ããïŒ
ãšã©ãŒã¡ãã»ãŒãžã«ãçŸåšã¬ã³ããªã³ã°ããŠããã³ã³ããŒãã³ããšãsetStateãåŒã³åºãããŠããã³ã³ããŒãã³ãã®äž¡æ¹ã®ååãå«ãããšãããšæããŸãã 誰ããããã®ããã«PRãéãããã§ããïŒ
ãããèŠãŠããããã§ãã ç§ãç¥ã£ãŠããã¹ããã€ã³ã¿ãŒã¯ãããŸããïŒ
@ samcooke98ãã®https://github.com/facebook/react/pull/18316ã®PRãéããŸãã
ä»ã®äººãææããŠããããã«ãApolloãªã©ã®ããã¯ã«ãµãã¹ã¯ãªãã·ã§ã³ããããããŒã¿ã®åä¿¡æã«ã¹ãã¢ãæŽæ°ããããšãããšããã®åé¡ãçºçããå¯èœæ§ããããŸãã ç°¡åãªä¿®æ£ã¯ã useEffect
ã䜿çšããããšã§ãã
export const useOrderbookSubscription = marketId => {
const { data, error, loading } = useSubscription(ORDERBOOK_SUBSCRIPTION, {
variables: {
marketId,
},
})
const formattedData = useMemo(() => {
// Don't dispatch in here.
}, [data])
// Don't dispatch here either
// Dispatch in a useEffect
useEffect(() => {
orderbookStore.dispatch(setOrderbookData(formattedData))
}, [formattedData])
return { data: formattedData, error, loading }
}
Hyperã§ãã®åé¡ã«çŽé¢ããŠããŸããããããã¯ã䜿çšããŠããããåŒã³åºãã¹ã¿ãã¯ããã®ã¬ã³ããªã³ã°åŒã³åºãã§äœãèŠã€ãããŸããã§ããã ããããã¹ã¿ãã¯ã®UNSAFE_componentWillReceiveProps
ã«åŒã³åºãããããŸããã componentDidUpdate
æŽæ°ãããšãåé¡ãä¿®æ£ãããŸããhttps://github.com/zeit/hyper/pull/4382
ããã誰ããå©ãããããããªããªãããã«ãããæçš¿ããŸãã
ããã§ãåãã§ãããUNSAFE_componentWillMountåŒã³åºãããããå€æŽ/åé€ãããšåé¡ãä¿®æ£ãããŸãã
ããããããã¯ã䜿çšããŠããããåŒã³åºãã¹ã¿ãã¯ããã®ã¬ã³ããªã³ã°åŒã³åºãã§äœãèŠã€ãããŸããã§ãã
ããã¯å¥åŠã«èãããŸãã ãã®ãšãããã®èŠåãã©ã®ããã«è¡šç€ºãããã®ãããããŸããã setStateãé¢æ°ã³ã³ããŒãã³ãã«å±ããŠããå Žåã«ã®ã¿èµ·åããŸãã ããªãã®ã¹ã¿ãã¯ã¯ã©ã®ãããªãã®ã§ããïŒ
ããããããã¯ã䜿çšããŠããããåŒã³åºãã¹ã¿ãã¯ããã®ã¬ã³ããªã³ã°åŒã³åºãã§äœãèŠã€ãããŸããã§ãã
ããã¯å¥åŠã«èãããŸãã ãã®ãšãããã®èŠåãã©ã®ããã«è¡šç€ºãããã®ãããããŸããã setStateãé¢æ°ã³ã³ããŒãã³ãã«å±ããŠããå Žåã«ã®ã¿èµ·åããŸãã ããªãã®ã¹ã¿ãã¯ã¯ã©ã®ãããªãã®ã§ããïŒ
Reduxã§ã³ã³ããŒãã³ããã¯ã©ã¹åããã³ã³ããŒãã³ãã«ãã©ã°ã€ã³ãé©çšããé¢æ°ã ãã¶ããããé¢æ°ã³ã³ããŒãã³ããšããŠã«ãŠã³ããããçç±ã§ããïŒ ãããããªãã©ã€ããµã€ã¯ã«ããã¯ãæŽæ°ãããšä¿®æ£ãããã®ã§ããããã
ããããªãã ãµã³ãããã¯ã¹ã§å€ç«ããäŸãäœæããŠã¿ãŠãã ããã ç§ã¯ããªããäºæããªãäœãä»ã®ããšãããŠãããããããªããšããäºæããããŸãã
å€ç«ããäŸã§ãããè€è£œã§ãããã©ããã¯ããããŸããã åå ãèŠã€ããã®ã«èŠåŽããã¹ã¿ãã¯ãã¬ãŒã¹ã«ãããæŽæ°ãä¿çãããŠãããããã©ã€ããµã€ã¯ã«ããã¯ãæŽæ°ãããšããã§ãã ããã¯ã©ããããããåé¡ãä¿®æ£ããŸããã
ããã§åé¡ãçºçãããšãã®ãªããžããªã確èªã§ã
UNSAFE_componentWillReceiveProps
ãšcomponentDidUpdate
äž¡æ¹ããã®æç¹ã§ã³ã³ããŒãã³ãã«å«ãŸããŠããïŒå®å
šã§ãªããã®ã誀ã£ãŠããã«æ®ãããŠããïŒãšããäºå®ãåå ã§ããããïŒ
ãã®èŠåã衚瀺ãããã¹ã¿ãã¯ãã¬ãŒã¹ã¯setScriptLoaded
ããã¯ãæããŠããŸãïŒã«ã¹ã¿ã ããã¯ã«ã€ããŠã¯ä»¥äžãåç
§ããŠãã ããïŒã ãããã£ãŠã useEffect
ã䜿çšããŠããŠãã setState
ãã³ãã©ãŒãä»ã®éåæã³ãŒã«ããã¯å
ã«ãã¹ããããŠããå ŽåïŒç§ã®å Žåã¯setTimeout
ãã¹ããããŠããå ŽåïŒãReactã¯èŠåãã¹ããŒããããã§ãã load
ã€ãã³ããã³ãã©ãŒïŒïŒ åããŠããã¯ã䜿çšããã®ã§ãã¢ããã€ã¹ãããã ããã°å¹žãã§ãã ããããšãããããŸããïŒ
/**
* Detect when 3rd party script is ready to use
*
* <strong i="11">@param</strong> {function} verifyScriptLoaded Callback to verify if script loaded correctly
* <strong i="12">@param</strong> {string} scriptTagId
*/
export const useScriptLoadStatus = (verifyScriptLoaded, scriptTagId) => {
let initLoadStatus = true; // HTML already includes script tag when rendered server-side
if (__BROWSER__) {
initLoadStatus = typeof verifyScriptLoaded === 'function' ? verifyScriptLoaded() : false;
}
const [isScriptLoaded, setScriptLoaded] = useState(initLoadStatus);
useEffect(() => {
if (!isScriptLoaded) {
// need to wrap in setTimeout because Helmet appends the script tags async-ly after component mounts (https://github.com/nfl/react-helmet/issues/146)
setTimeout(() => {
let newScriptTag = document.querySelector(`#${scriptTagId}`);
if (newScriptTag && typeof verifyScriptLoaded === 'function') {
newScriptTag.addEventListener('load', () => {
return verifyScriptLoaded() ? setScriptLoaded(true) : null;
});
// double check if script is already loaded before the event listener is added
return verifyScriptLoaded() ? setScriptLoaded(true) : null;
}
}, 100);
}
});
return isScriptLoaded;
};
@LabhanshAgrawal
UNSAFE_componentWillReceivePropsãšcomponentDidUpdateã®äž¡æ¹ããã®æç¹ã§ã³ã³ããŒãã³ãã«å«ãŸããŠããïŒå®å šã§ãªããã®ã誀ã£ãŠããã«æ®ãããŠããïŒãšããäºå®ãåå ã§ããå¯èœæ§ããããŸããïŒ
ããã§ã¯ãã©ã€ããµã€ã¯ã«ã¡ãœããã¯ãŸã£ããé¢ä¿ãªããšæããŸãã ããããããªãã®äŸã§äœãããããããšèšã£ãŠããçç±ã§ãã
@suhanwCodeSandboxã§å®å šãªäŸãæäŸããŠãã ããã ãã®èŠåã®åå ãšãªãã³ãŒãã«åé¡ã¯ãããŸããã
@LabhanshAgrawalãã«ã¹ã¿ãã¯ãæçš¿ã§ããŸããïŒ ããªãã®UNSAFE_componentWillReceiveProps
ïŒã¬ã³ããªã³ã°ãšåçïŒãå¥ã®ã³ã³ããŒãã³ãã§setState
ãåŒã³åºããŠããããšãèµ·ãã£ãŠããã®ã§ã¯ãªãããšæããŸãã
backend.js:6 Warning: Cannot update a component from inside the function body of a different component.
in Term (created by _exposeDecorated(Term))
in _exposeDecorated(Term) (created by DecoratedComponent)
in DecoratedComponent (created by TermGroup_)
in TermGroup_ (created by ConnectFunction)
in ConnectFunction (created by Connect(TermGroup_))
in Connect(TermGroup_) (created by _exposeDecorated(TermGroup))
in _exposeDecorated(TermGroup) (created by DecoratedComponent)
in DecoratedComponent (created by Terms)
in div (created by Terms)
in div (created by Terms)
in Terms (created by _exposeDecorated(Terms))
in _exposeDecorated(Terms) (created by DecoratedComponent)
in DecoratedComponent (created by ConnectFunction)
in ConnectFunction (created by Connect(DecoratedComponent))
in Connect(DecoratedComponent) (created by Hyper)
in div (created by Hyper)
in div (created by Hyper)
in Hyper (created by _exposeDecorated(Hyper))
in _exposeDecorated(Hyper) (created by DecoratedComponent)
in DecoratedComponent (created by ConnectFunction)
in ConnectFunction (created by Connect(DecoratedComponent))
in Connect(DecoratedComponent)
in Provider
r @ backend.js:6
printWarning @ react-dom.development.js:88
error @ react-dom.development.js:60
warnAboutRenderPhaseUpdatesInDEV @ react-dom.development.js:23260
scheduleUpdateOnFiber @ react-dom.development.js:21196
dispatchAction @ react-dom.development.js:15682
checkForUpdates @ connectAdvanced.js:88
handleChangeWrapper @ Subscription.js:97
(anonymous) @ Subscription.js:23
batchedUpdates$1 @ react-dom.development.js:21887
notify @ Subscription.js:19
notifyNestedSubs @ Subscription.js:92
checkForUpdates @ connectAdvanced.js:77
handleChangeWrapper @ Subscription.js:97
(anonymous) @ Subscription.js:23
batchedUpdates$1 @ react-dom.development.js:21887
notify @ Subscription.js:19
notifyNestedSubs @ Subscription.js:92
handleChangeWrapper @ Subscription.js:97
dispatch @ redux.js:222
e @ VM64:1
(anonymous) @ effects.ts:11
(anonymous) @ write-middleware.ts:14
(anonymous) @ index.js:11
(anonymous) @ plugins.ts:538
(anonymous) @ plugins.ts:540
(anonymous) @ index.js:11
dispatch @ redux.js:638
(anonymous) @ sessions.ts:124
(anonymous) @ index.js:8
dispatch @ VM64:1
onResize @ terms.ts:62
(anonymous) @ term.js:179
e.fire @ xterm.js:1
t.resize @ xterm.js:1
e.resize @ xterm.js:1
e.fit @ xterm-addon-fit.js:1
fitResize @ term.js:291
UNSAFE_componentWillReceiveProps @ term.js:408
callComponentWillReceiveProps @ react-dom.development.js:12998
updateClassInstance @ react-dom.development.js:13200
updateClassComponent @ react-dom.development.js:17131
beginWork @ react-dom.development.js:18653
beginWork$1 @ react-dom.development.js:23210
performUnitOfWork @ react-dom.development.js:22185
workLoopSync @ react-dom.development.js:22161
performSyncWorkOnRoot @ react-dom.development.js:21787
(anonymous) @ react-dom.development.js:11111
unstable_runWithPriority @ scheduler.development.js:653
runWithPriority$1 @ react-dom.development.js:11061
flushSyncCallbackQueueImpl @ react-dom.development.js:11106
flushSyncCallbackQueue @ react-dom.development.js:11094
batchedUpdates$1 @ react-dom.development.js:21893
notify @ Subscription.js:19
notifyNestedSubs @ Subscription.js:92
handleChangeWrapper @ Subscription.js:97
dispatch @ redux.js:222
e @ VM64:1
(anonymous) @ effects.ts:11
(anonymous) @ write-middleware.ts:14
(anonymous) @ index.js:11
(anonymous) @ plugins.ts:538
(anonymous) @ plugins.ts:540
(anonymous) @ index.js:11
dispatch @ redux.js:638
effect @ ui.ts:60
(anonymous) @ effects.ts:13
(anonymous) @ write-middleware.ts:14
(anonymous) @ index.js:11
(anonymous) @ plugins.ts:538
(anonymous) @ plugins.ts:540
(anonymous) @ index.js:11
dispatch @ redux.js:638
(anonymous) @ ui.ts:54
(anonymous) @ index.js:8
dispatch @ VM64:1
(anonymous) @ index.tsx:162
emit @ events.js:210
(anonymous) @ rpc.ts:31
emit @ events.js:210
onMessage @ init.ts:50
@gaearonã¯è¿ éãªå¯Ÿå¿ã«æè¬ããŸãã CodeSandboxã§äŸãäœæããæ¹æ³ãèŠã€ããŸãïŒããã¯ææŠçã§ãïŒãããããŸã§ã®éãããã¯ç§ã®å®å šãªã¹ã¿ãã¯ãã¬ãŒã¹ã§ã
ç§ã®ã«ã¹ã¿ã ããã¯ãæãè¡ã¯æ¬¡ã®ãšããã§ãïŒ https ïŒ//gist.github.com/suhanw/bcc2688bba131df8301dae073977654f#file -stack-trace-L144
ã«ã¹ã¿ã ããã¯ã®ååŸã®ã¹ã¿ãã¯ãã¬ãŒã¹ã«ãããã«èª¿æ»ããå¿ èŠããããã®ããããã©ããã確èªããŠãç¥ããããã ããã°çŽ æŽããããšæããŸãã ããããšãïŒ
@LabhanshAgrawalã¹ã¿ãã¯å
ã§ã UNSAFE_componentWillReceiveProps
ã¯ããã€ãã®fitResize
ãåŒã³åºããReduxã¢ã¯ã·ã§ã³ããã£ã¹ãããããŸããããã«ãããäžé£ã®ã³ã³ããŒãã³ããæŽæ°ãããŸãã ãããã£ãŠãåé¡ã ããã§ããããããcomponentDidUpdate
ã«å€æŽãããšæ©èœããŸãã
@suhanwã¹ã¿ãã¯ã§ã¯ã ModuleImpressionTracker
ãšåŒã°ãããã®ããã³ã³ã¹ãã©ã¯ã¿ãŒäžã«Reduxã¢ã¯ã·ã§ã³ããã£ã¹ãããããŠããããã«èŠããŸãã ã³ã³ã¹ãã©ã¯ã¿ãŒã«å¯äœçšããã£ãŠã¯ãªããŸããã ãããåé¡ã®åå ã§ãããããã¯ã§ã¯ãªããšæããŸãã
ãªãã»ã©ã UNSAFE_componentWillReceiveProps
ã¯ã¬ã³ããªã³ã°ãšããŠã«ãŠã³ããããŸããã componentDidUpdate
ã¯ã«ãŠã³ããããªããšããããšãããããåãé€ããŸãã
setStateãå®è¡ããæ©èœã³ã³ããŒãã³ããšããã¯ã®åé¡ã§ããããšãå°ãæ確ã«ã§ããŸããïŒäžèšã®èª¬æããã¯æ確ã«ç解ã§ããŸããã§ããã
質åãå°ãã°ãããŠããããç§ã®æã¡åž°ããééã£ãŠããå Žåã¯ããè©«ã³ããŸããç§ã¯ããã«å°ãæ
£ããŠããŸããã
@LabhanshAgrawal
setStateãå®è¡ããæ©èœã³ã³ããŒãã³ããšããã¯ã®åé¡ã§ããããšãå°ãæ確ã«ã§ããŸããïŒäžèšã®èª¬æããã¯æ確ã«ç解ã§ããŸããã§ããã
æ£çŽãªãšãããéäžã«ãã¹ãŠã®Reduxãå«ãŸããŠãããããèªåèªèº«ãããããããŸããã React Reduxãã©ã®ããã«å®è£ ãããŠãããã«ãããããªãæ··ä¹±ããŸãã 誰ããReactã ããå«ã¿ãã¯ã©ã¹ã³ã³ããŒãã³ãã䜿çšããæ確ãªåçŸãåŸãããšãã§ããã°çŽ æŽãããã§ãããã
ããã§ããã¹ã¿ãã¯ãã¬ãŒã¹ããããã貌ãä»ããããŠããããã§ãã¿ã€ãã«é¢ä¿ãªããå®éã®åé¡ã®å®éã®åçŸã¯å€ããããŸããã
urql
ã¯@gaearonã察象ãšããŠãããš
<Todos />
ããŠã³ãããŸãããããã«ãããããŒã¿ããã§ãããããŠã¬ã³ããªã³ã°ãããŸããurqlClient
æ¥ç¶ãããã¹ããªãŒã ãèšå®ããŸãã<Todos />
ãã¬ã³ããªã³ã°ãããšãåãã¯ãšãªãšå€æ°ã®çµã¿åãããçæããããããæåã®ã¹ãããã®<Todos />
ã®çµæãæŽæ°ãããŸããuse-subscription
ã¯äž¡æ¹ã«å¯ŸããŠããªã¬ãŒãããŸããåçŸ-æåã®ã¯ãšãªã衚瀺ãããããäžéšã«ãã[éã]ãæŒããŸãã
æŽæ°ããã¥ãŒã«å
¥ããããšã¯ã§ããŸãããã³ã³ããã¹ãã䜿çšããŠtop-down
ã¬ã³ããªã³ã°ãè¡ããªãéãããã®åé¡ãåé¿ããããšã¯ã§ããŸããã çè«çã«ã¯ãããã¯ãã®å Žåã®æå³ãããåäœã§ãã ãªã¬ãŒããããã©ã®ããã«åé¿ããã®ãèå³ããããŸãã
ç·šéïŒ use-subscription
ã®getCurrentValue
ã®éã«ãã¹ãŠã®ãµãã¹ã¯ã©ã€ããŒãæŽæ°ããããã«ããªã¬ãŒããªãããšã§ãurqlã®å Žåã®è§£æ±ºçãèŠã€ããå¯èœæ§ããããŸã
https://github.com/FormidableLabs/urql/commit/3a597dd92587ef852c18139e9781e853f763e930
ããŠãããã詳ãã調ã¹ãŠã¿ããšãåœåã®æå³ãããå€ãã®å ŽåïŒã¯ã©ã¹ãªã©ïŒã«èŠåããŠãããšæããŸãã ãããã®ããã€ããé»ãããããšãæ€èšããŸãã
@JoviDeCroockãã®äŸã¯ã urql
ãäœãããã®ãããããªããããããŸã圹ã«ç«ã¡ãŸããã :-)ãã¿ãŒã³ã«é¢ãããã£ãŒãããã¯ãå¿
èŠãªå Žåã¯ããã®ãã¿ãŒã³ãåå¥ã«ç€ºããµã³ãããã¯ã¹ãæºåã§ããŸããïŒ
@JoviDeCroockã¯ãã getCurrentValue
ã¯ééããªãå¯äœçšãæå³ãããã®ã§ã¯ãããŸã
ã«ã¹ã¿ã ããã¯ã®ã«ãŒãã¹ã³ãŒãå ã§reduxã¢ã¯ã·ã§ã³ããã£ã¹ããããããšããã®èŠåã衚瀺ããããšããåé¡ããããŸããã
function useCustomHook() {
const dispatch = useDispatch()
const value = useSomeOtherHook()
dispatch(action(value))
}
ãã£ã¹ããããuseEffect
ã§ã©ããããããšã§ããããä¿®æ£ããŸããã
@Glinkisããã¯é¢ä¿ãªãæªããã¿ãŒã³ã®ããã«èãããŸãã ã³ã³ããŒãã³ããã¬ã³ããªã³ã°ããããã³ã«ããªãŒå šäœã«éç¥ãããã®ã¯ãªãã§ããïŒ
@gaearonã¯ããç§ãã¡ã解決ããããšããŠããåé¡ã¯ãããã§ãããã説æã
@Glinkisããã¯é¢ä¿ãªãæªããã¿ãŒã³ã®ããã«èãããŸãã ã³ã³ããŒãã³ããã¬ã³ããªã³ã°ããããã³ã«ããªãŒå šäœã«éç¥ãããã®ã¯ãªãã§ããïŒ
reduxã®ç¶æ ãã«ãŒãã®IDãšåæãããå¿ èŠããããããã«ãŒããå€æŽããããšãã«ãã®æŽæ°ããã£ã¹ãããããŸãã
ããã¯æé©ã§ã¯ãªãå¯èœæ§ãããããšã¯ããã£ãŠããŸãããã»ã¬ã¯ã¿ãŒå ã®ã«ãŒãã£ã³ã°ããŒã¿ã«ã¢ã¯ã»ã¹ããä»ã®æ¹æ³ã¯èŠã€ãããŸããã§ããã
@Glinkisã«ãŒãããŒã¿ã¯ã©ãããæ¥ãŠããŸããïŒ
@JoviDeCroockãã®ãã¿ãŒã³ã«å¯Ÿããææ°ã®æšå¥šäºé ã¯ãã«ã¹ã¿ã ã®ã¹ã±ãžã¥ãŒã«ãããã¬ããŒãžã³ã¬ã¯ã·ã§ã³ãã¹ã ãšæããŸãã
@Glinkisã«ãŒãããŒã¿ã¯ã©ãããæ¥ãŠããŸããïŒ
ãããç§ã«å±ãããã©ããã¯ããããŸããããããã¯ç§ã®ããã¯ã§ãã
export function useOpenFolder() {
const dispatch = useDispatch()
const match = useRouteMatch('/:workspace/(super|settings)?/:type?/:id?/(item)?/:item?')
const { id, item } = match?.params || {}
useEffect(() => {
dispatch(
openFolder({
id: id || '',
item: item || '',
})
)
}, [dispatch, item, id])
}
åŸã§ãã®ç¶æ ã次ã®ãããªã»ã¬ã¯ã¿ãŒã«äœ¿çšããŸãã
export const getActiveItem = createSelector(
[getActiveFolderItem, getItems],
(activeItem, items) => items.all[activeItem]
)
@Glinkisãããããã§ãŸãšããŸããããããããç§ã®ææ¡ã¯ã芪ã³ã³ããŒãã³ãã§useRouteMatch
ãèªã¿åããIDãå°éå
·ãšããŠæž¡ããŠãããéåžžã©ããã»ã¬ã¯ã¿ãŒã§å°éå
·ãèªã¿åãããšã§ãã ïŒæè¿ã®Reduxã§ãããã©ã®ããã«è¡ããããã¯å®éã«ã¯ããããŸããããäœããã®æ¹æ³ãããã¯ãã§ããïŒ
ãªãã»ã©ã
UNSAFE_componentWillReceiveProps
ã¯ã¬ã³ããªã³ã°ãšããŠã«ãŠã³ããããŸãããcomponentDidUpdate
ã¯ã«ãŠã³ããããªããšããããšãããããåãé€ããŸãã
@LabhanshAgrawalãã®éãã§ãã ããã«ããã€ãã®èæ¯èª¬æïŒ
æŠå¿µçã«ã¯ãReactã¯2ã€ã®ãã§ãŒãºã§æ©èœããŸãã
- ã¬ã³ããªã³ã°ãã§ãŒãºã§ã¯ãDOMãªã©ã«ã©ã®ãããªå€æŽãå ããå¿ èŠããããã決å®ããŸãã ãã®ãã§ãŒãºã§ã¯ãReactã¯
render
ãåŒã³åºãããã®çµæãåã®ã¬ã³ããªã³ã°ãšæ¯èŒããŸãã- ã³ããããã§ãŒãºã¯ãReactãå€æŽãé©çšãããšãã§ãã ïŒReact DOMã®å Žåãããã¯ReactãDOMããŒããæ¿å ¥ãæŽæ°ãããã³åé€ãããšãã§ããïŒReact
componentDidUpdate
ããã®ãã§ãŒãºã§componentDidMount
ãcomponentDidUpdate
ãªã©ã®ã©ã€ããµã€ã¯ã«ãåŒã³åºããŸããã³ããããã§ãŒãºã¯éåžžéåžžã«é«éã§ãããã¬ã³ããªã³ã°ãé ããªãå¯èœæ§ããããŸãã ãã®ããã次ã®äžŠè¡ã¢ãŒãïŒããã©ã«ãã§ã¯ãŸã æå¹ã«ãªã£ãŠããŸããïŒã¯ãã¬ã³ããªã³ã°äœæ¥ãåå²ãããã©ãŠã¶ãŒã®ãããã¯ãåé¿ããããã«äœæ¥ãäžæåæ¢ããã³åéããŸãã ããã¯ãReactãã³ãããããåã«ã¬ã³ããªã³ã°ãã§ãŒãºã®ã©ã€ããµã€ã¯ã«ãè€æ°ååŒã³åºãå ŽåãããŸã£ããã³ãããããã«åŒã³åºãå Žåãããããšãæå³ããŸãïŒãšã©ãŒãŸãã¯åªå 床ã®é«ãäžæã®ããïŒã
ã¬ã³ããªã³ã°ãã§ãŒãºã®ã©ã€ããµã€ã¯ã«ã«ã¯ã次ã®ã¯ã©ã¹ã³ã³ããŒãã³ãã¡ãœãããå«ãŸããŸãã
constructor
componentWillMount
ïŒãŸãã¯UNSAFE_componentWillMount
ïŒcomponentWillReceiveProps
ïŒãŸãã¯UNSAFE_componentWillReceiveProps
ïŒcomponentWillUpdate
ïŒãŸãã¯UNSAFE_componentWillUpdate
ïŒgetDerivedStateFromProps
shouldComponentUpdate
render
setState
ã¢ããããŒã¿é¢æ°ïŒæåã®åŒæ°ïŒäžèšã®ã¡ãœããã¯è€æ°ååŒã³åºãããå¯èœæ§ããããããå¯äœçšãå«ãŸããŠããªãããšãéèŠã§ãã ãã®ã«ãŒã«ãç¡èŠãããšãã¡ã¢ãªãªãŒã¯ãç¡å¹ãªã¢ããªã±ãŒã·ã§ã³ç¶æ ãªã©ãããŸããŸãªåé¡ãçºçããå¯èœæ§ããããŸãã æ®å¿µãªããããããã®åé¡ã¯é決å®è«çã§ããããšãå€ãããããããã®åé¡ãæ€åºããã®ã¯é£ããå ŽåããããŸãã
ããŠãããã詳ãã調ã¹ãŠã¿ããšãåœåã®æå³ãããå€ãã®å ŽåïŒã¯ã©ã¹ãªã©ïŒã«èŠåããŠãããšæããŸãã ãããã®ããã€ããé»ãããããšãæ€èšããŸãã
æå³ãã以äžã®ããšã ãšæããŸãããã¯ã©ã¹ã䜿ã£ãŠãããžã§ã¯ããæ¹åããã®ã«åœ¹ç«ã€ã®ã§ãæã£ãŠããã®ã¯è¯ãããšã ãšæããŸãã
ãã®èªæã®ãšã©ãŒã¡ãã»ãŒãžãå¥ã®ã³ã³ããŒãã³ãã®é¢æ°æ¬äœã®å éšããã³ã³ããŒãã³ããæŽæ°ã§ããŸããã
ã€ãŸããã³ã³ããŒãã³ããåŒã³åºãã®ã§ã¯ãªããé¢æ°ãšããŠå®è¡ããŸãã
ãã®ãããªäŸïŒ
const App = () => {
const fetchRecords = () => {
return <div>Loading..</div>;
};
return fetchRecords() // and not like <FetchRecords /> unless it is functional component.
};
export default App;
@rpateldããªãã瀺ããŠããäŸã¯ããã®èŠåã«é¢é£ããŠãããšã¯æããŸããã
https://github.com/facebook/react/pull/18330ã¯ãçºç ²ãéå§ããã€ããããªãã£ãã±ãŒã¹ã解決ã
react@experimental
+ react-redux
+ redux
ã§ããã®åé¡ã«çŽé¢ããŠããŸãã
ã³ãŒãã¯æ¬¡ã®ããã«ãªããŸãã
import React, { Suspense } from 'react'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import { Redirect } from 'react-router-dom'
import PropTypes from 'prop-types'
import { userActions, cabinetActions, tokensActions } from '../../actions'
import { CircularProgress } from '@material-ui/core'
import { api } from './api'
const Cabinet = ({ resource }) => {
resource.read()
return <h1>cabinet</h1>
}
Cabinet.propTypes = {
resource: PropTypes.shape({
read: PropTypes.func
})
}
const CabinetPage = ({
failedToLoad,
tokensRefreshFailed,
logout,
loadCabinet,
clearTokens,
clearCabinet
}) => {
if (tokensRefreshFailed || failedToLoad) {
clearTokens()
clearCabinet()
logout()
return <Redirect to='/login' />
}
return (
<Suspense fallback={<CircularProgress />}>
<Cabinet resource={loadCabinet()} />
</Suspense>
)
}
CabinetPage.propTypes = {
loadCabinet: PropTypes.func,
failedToLoad: PropTypes.bool,
tokensRefreshFailed: PropTypes.bool,
logout: PropTypes.func,
clearTokens: PropTypes.func,
clearCabinet: PropTypes.func
}
const mapStateToProps = ({
alert,
tokens: { tokensRefreshFailed },
cabinet: { failedToLoad }
}) => ({
alert,
tokensRefreshFailed,
failedToLoad
})
const mapDispatchToProps = dispatch =>
bindActionCreators(
{
cabinetLoad: cabinetActions.load,
logout: userActions.logoutWithoutRedirect,
loadCabinet: api.loadCabinet,
clearCabinet: cabinetActions.clear,
clearTokens: tokensActions.clear
},
dispatch
)
export default connect(mapStateToProps, mapDispatchToProps)(CabinetPage)
loadCabinet()
ã¯ãåæããã¥ã¡ã³ããèšãããã«ã3ãã§ãŒãºã¬ã³ããªã³ã°ã®éåæã¢ã¯ã·ã§ã³ããã£ã¹ããããã read()
propã䜿çšããŠãªããžã§ã¯ããè¿ããŸãã
ãã ããããã§ã¯èŠªã®æŽæ°ã確èªã§ããŸããã
@ h0tw4t3rã³ã³ããŒãã³ãã®ã¬ã³ããªã³ã°äžã«Reduxã¢ã¯ã·ã§ã³ããã£ã¹ãããããŠããŸãã ããã¯ãµããŒããããŠããŸããããããŠããã¯èŠåãäœã§ãããã«ã€ããŠã§ãã ãã®ã±ãŒã¹ïŒãªãã€ã¬ã¯ãïŒãé©åã«åŠçããæ¹æ³ã«ã€ããŠReact Routerã®å°é家ã«å°ããã®ãæåã§ããããã®éšåã«ã€ããŠã¯åœ¹ã«ç«ã¡ãŸããã
䞊è¡ã¢ãŒãã«é¢ããŠã¯ãReduxã¯çŸåšäžè¬çã«äºææ§ããªãããšã«æ³šæããŠãã ããã ãããã£ãŠãCMãè©ŠããŠããå Žåã¯ããããé¿ããããšæããããããŸããã
ã¯ã©ã¹ã«å¯Ÿãããã®èŠåã®éå°çºç«ãä¿®æ£ããReactã®ãããããŸããªããªãªãŒã¹ããäºå®ã§ãã ãããã£ãŠããããçºçããå Žåã¯ãæ°æ¥åŸ ã£ãŠããã16.13.1ããªãªãŒã¹ããããè©ŠããŠã¿ãããšãæ€èšããŠãã ããã
åå ãæ¢ãç¶ãããå Žåã¯ã httpsïŒ //github.com/facebook/react/issues/18178#issuecomment-595846312ã§ãã®æ¹æ³ã説æããŠ
ã¯ã©ã¹ã³ã³ããŒãã³ãã§äœ¿çšããããšãã«åãããžãã¯ãæ©èœïŒããã¯ïŒãèŠåãçºããã®ã«èŠåãçºããªãã®ã¯éåžžã«å¥åŠã ãšæããŸãã
æ©èœã³ã³ããŒãã³ãïŒããã¯ïŒïŒ
import React, { Component } from "react"
import SortableTree from "react-sortable-tree"
import "react-sortable-tree/style.css"
const data = [
{
title: "Windows 10",
subtitle: "running",
children: [
{
title: "Ubuntu 12",
subtitle: "halted",
children: [
{
title: "Debian",
subtitle: "gone"
}
]
},
{
title: "Centos 8",
subtitle: "hardening"
},
{
title: "Suse",
subtitle: "license"
}
]
}
]
const nodeInfo = row => console.log(row)
export default class App extends Component {
constructor(props) {
super(props)
this.state = {
searchString: "",
searchFocusIndex: 0,
searchFoundCount: null,
treeData: data
}
}
render() {
const { searchString, searchFocusIndex, searchFoundCount } = this.state
const customSearchMethod = ({ node, searchQuery }) =>
searchQuery &&
((node.title &&
node.title.toLowerCase().indexOf(searchQuery.toLowerCase()) > -1) ||
(node.subtitle &&
node.subtitle.toLowerCase().indexOf(searchQuery.toLowerCase()) > -1))
const selectPrevMatch = () =>
this.setState({
searchFocusIndex:
searchFocusIndex !== null
? (searchFoundCount + searchFocusIndex - 1) % searchFoundCount
: searchFoundCount - 1
})
const selectNextMatch = () =>
this.setState({
searchFocusIndex:
searchFocusIndex !== null
? (searchFocusIndex + 1) % searchFoundCount
: 0
})
return (
<div>
<h2>Find the needle!</h2>
<form
style={{ display: "inline-block" }}
onSubmit={event => {
event.preventDefault()
}}
>
<input
id="find-box"
type="text"
placeholder="Search..."
style={{ fontSize: "1rem" }}
value={searchString}
onChange={event =>
this.setState({ searchString: event.target.value })
}
/>
<button
type="button"
disabled={!searchFoundCount}
onClick={selectPrevMatch}
>
<
</button>
<button
type="submit"
disabled={!searchFoundCount}
onClick={selectNextMatch}
>
>
</button>
<span>
{searchFoundCount > 0 ? searchFocusIndex + 1 : 0}
/
{searchFoundCount || 0}
</span>
</form>
<div style={{ height: 300 }}>
<SortableTree
treeData={this.state.treeData}
onChange={treeData => this.setState({ treeData })}
searchMethod={customSearchMethod}
searchQuery={searchString}
searchFocusOffset={searchFocusIndex}
searchFinishCallback={matches =>
this.setState({
searchFoundCount: matches.length,
searchFocusIndex:
matches.length > 0 ? searchFocusIndex % matches.length : 0
})
}
generateNodeProps={row => {
return {
title: row.node.title,
subtitle: (
<div style={{ lineHeight: "2em" }}>{row.node.subtitle}</div>
),
buttons: [
<button
type="button"
className="btn btn-outline-success"
style={{
verticalAlign: "middle"
}}
onClick={() => nodeInfo(row)}
>
â¹
</button>
]
}
}}
/>
</div>
</div>
)
}
}
ã¯ã©ã¹ã³ã³ããŒãã³ãïŒ
import React from "react";
import SortableTree from "react-sortable-tree";
import "react-sortable-tree/style.css";
const data = [
{
title: "Windows 10",
subtitle: "running",
children: [
{
title: "Ubuntu 12",
subtitle: "halted",
children: [
{
title: "Debian",
subtitle: "gone"
}
]
},
{
title: "Centos 8",
subtitle: "hardening"
},
{
title: "Suse",
subtitle: "license"
}
]
}
];
const nodeInfo = row => console.log(row);
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
searchString: "",
searchFocusIndex: 0,
searchFoundCount: null,
treeData: data
};
}
render() {
const { searchString, searchFocusIndex, searchFoundCount } = this.state;
const customSearchMethod = ({ node, searchQuery }) =>
searchQuery &&
((node.title &&
node.title.toLowerCase().indexOf(searchQuery.toLowerCase()) > -1) ||
(node.subtitle &&
node.subtitle.toLowerCase().indexOf(searchQuery.toLowerCase()) > -1));
const selectPrevMatch = () =>
this.setState({
searchFocusIndex:
searchFocusIndex !== null
? (searchFoundCount + searchFocusIndex - 1) % searchFoundCount
: searchFoundCount - 1
});
const selectNextMatch = () =>
this.setState({
searchFocusIndex:
searchFocusIndex !== null
? (searchFocusIndex + 1) % searchFoundCount
: 0
});
return (
<div>
<h2>Find the needle!</h2>
<form
style={{ display: "inline-block" }}
onSubmit={event => {
event.preventDefault();
}}
>
<input
id="find-box"
type="text"
placeholder="Search..."
style={{ fontSize: "1rem" }}
value={searchString}
onChange={event =>
this.setState({ searchString: event.target.value })
}
/>
<button
type="button"
disabled={!searchFoundCount}
onClick={selectPrevMatch}
>
<
</button>
<button
type="submit"
disabled={!searchFoundCount}
onClick={selectNextMatch}
>
>
</button>
<span>
{searchFoundCount > 0 ? searchFocusIndex + 1 : 0}
/
{searchFoundCount || 0}
</span>
</form>
<div style={{ height: 300 }}>
<SortableTree
treeData={this.state.treeData}
onChange={treeData => this.setState({ treeData })}
searchMethod={customSearchMethod}
searchQuery={searchString}
searchFocusOffset={searchFocusIndex}
searchFinishCallback={matches =>
this.setState({
searchFoundCount: matches.length,
searchFocusIndex:
matches.length > 0 ? searchFocusIndex % matches.length : 0
})
}
generateNodeProps={row => {
return {
title: row.node.title,
subtitle: (
<div style={{ lineHeight: "2em" }}>{row.node.subtitle}</div>
),
buttons: [
<button
type="button"
className="btn btn-outline-success"
style={{
verticalAlign: "middle"
}}
onClick={() => nodeInfo(row)}
>
â¹
</button>
]
};
}}
/>
</div>
</div>
);
}
}
@radulleããèªäœã¯ããŸã圹ã«ç«ã¡ãŸããã CodeSandboxã«å ¥ããŠã¿ãŸããããæ©èœããŸããïŒ https ïŒ//codesandbox.io/s/clever-taussig-9xixs
@gaearonã³ãŒããµã³ãããã¯ã¹ãäœæãããã£ãã®ã§ãããææ°ããŒãžã§ã³ã®ã©ã€ãã©ãªã«ã¯ããã€ãã®åé¡ããããŸãã å€ãããŒãžã§ã³ã§ã¯ãšã©ãŒã¯ã¹ããŒãããŸããã çŸæç¹ã§ã¯ããããåçŸããå¯äžã®æ¹æ³ã¯ãããŒã«ã«ã§Create ReactAppã§ã¹ãã³ã¢ããããããšã ãšæãããŸã:(
@radulle CodeSandboxã§æ©èœããããŒãžã§ã³ãè©Šãããšãã§ããŸããïŒ
@gaearon 2.6.2ã¯æ©èœãã次ã®èšå®ã§ãšã©ãŒ/èŠåãã¹ããŒããŸãã
ãããã£ãŠãåãèšå®ã®å ŽåïŒ
æ©èœã³ã³ããŒãã³ãïŒãšã©ãŒ/èŠå
ã¯ã©ã¹ã³ã³ããŒãã³ãïŒãšã©ãŒ/èŠåãªã
å€åç§ã¯äœããéããŠããŠããããã¯åçã§ã¯ãããŸããã
ãããããã¯ç§ãhttps://github.com/facebook/react/issues/18178#issuecomment-600369392ã§åç §ããã±ãŒã¹ã®1ã€ã§ãã ãã®å ŽåãèŠåããã¥ãŒãããŸãã èŠåèªäœã¯æ£åœã§ãããããªããæ£ããèšãããã«ãæŠå¿µçã«ã¯ã¯ã©ã¹ã§ãåé¡ã§ãã ãã ãããã®äžäžèŽã¯æå³ããªããªããããã¯ã©ã¹ïŒãã®äŸã§ã¯ïŒããã®ãã®ã§ããå Žåã¯ãä»ã®ãšããäž¡æ¹ã®å Žåã§ãã¥ãŒãããŸãã
ãšãã§ã¯ãããã§ã¯ãªããã¬ã³ããŒé¢æ°ããç¶æ ã®æŽæ°ãèµ·åããæ£åœãªãŠãŒã¹ã±ãŒã¹ããããšæããŸããããã¯ãå®è¡é åºãç¶æããããšã§ãã
å®çšçãªäŸã§èª¬æãããšãç§ãã¡ã®ã¢ããªã«ã¯ããã³ãããªã¹ãã管çããããã®ç¬èªã®ã·ã¹ãã ããããŸãã
次ã®ããã«ããã®ã³ã³ããã¹ãã«ãã¬ããã¯ã©ã ãè¿œå ã§ããããã¯ããããŸãã
const addBreadcrumb = useAddBreadcrumb();
addBreadcrumb(<Breadcrumb>{item.name}</Breadcrumb>, [item.name]);
ãã¬ããã¯ã©ã æ§é ãç¶æããå¿ èŠããªããããããã¯éåžžã«å®çšçã§ãããã®æ§é ã¯ã³ãŒãèªäœã§å®£èšãããŠããŸãã ã«ãŒããã¢ããªã±ãŒã·ã§ã³ã®å¥ã®éšåã«ç§»åãããå Žåããã¬ããã¯ã©ã ã·ã¹ãã ã¯æ©èœãç¶ããŸãã
ãããã£ãŠã react-router
ãšçµã¿åããããšã次ã®ãããªããšãã§ããŸãã
// Main/index.tsx
import { useAddBreadcrumb } from 'components/Breadcrumbs';
import React from 'react';
import Home from './Home';
import Movies from './Movies';
const Main = () => {
const addBreadcrumb = useAddBreadcrumb();
addBreadcrumb(<Breadcrumb to="/">Home</Breadcrumb>, []);
return <Switch>
<Route path="/movies">
<Movies />
</Route>
<Route path="/" />
<Home />
</Route>
</Switch>
}
// Movies/index.tsx
import { useAddBreadcrumb } from 'components/Breadcrumbs';
import React from 'react';
import Detail from './Detail';
import Master from './Master';
const Movies = ({ url }) => {
const addBreadcrumb = useAddBreadcrumb();
addBreadcrumb(<Breadcrumb to={url}>Movies</Breadcrumb>, [url]);
return <Switch>
<Route path="/:id">
<Detail />
</Route>
<Route path="/" />
<Master />
</Route>
</Switch>
}
// Movies/Detail/index.tsx
import Breadcrumbs, { useAddBreadcrumb } from 'components/Breadcrumbs';
import React from 'react';
import { useRouteMatch } from 'react-router-dom';
const MovieDetail = ({ url }) => {
const addBreadcrumb = useAddBreadcrumb();
const { params: { id } } = useRouteMatch<{ id: string; }>();
const movie = useMovie(id);
addBreadcrumb(
<Breadcrumb to={url}>{movie?.name}</Breadcrumb>,
[movie?.name, url]
);
return <div>
<Breadcrumbs />
</div>
}
ããã§ã /movies/gone-with-the-wind
ãšããã¬ããã¯ã©ã ã¯æ¬¡ã®ããã«ãªããŸãã
Home > Movies > Gone with the wind
ããŠããããç§ã®ãã€ã³ãã§ãããããæ©èœããããã«ã¯ãå®è¡é åºãä¿èšŒãããŠããå¿
èŠããããŸãã ãã®å Žåãå®è¡é åºã¯æããã§ããæåã«Main
ã¬ã³ããªã³ã°ããã次ã«Movies
å«ãåãã¬ã³ããªã³ã°ãããæåŸã«MovieDetail
ã¬ã³ããªã³ã°ãããŸãã ãã®å Žåã addBreadcrumb
åŒã³åºãã¯æ£ããé åºã§å®è¡ãããŸãã
çŸåšãå€æŽãã°ã«ã¯æ¬¡ã®ããã«èšèŒãããŠããŸãã
ã¬ã³ããªã³ã°ã®çµæãšããŠæå³çã«å¥ã®ã³ã³ããŒãã³ãã®ç¶æ ãå€æŽããããšãããŸããªã±ãŒã¹ã§ã¯ãsetStateåŒã³åºããuseEffectã«ã©ããããããšãã§ããŸãã
ããã¯ç¢ºãã«ãå¥ã®ã³ã³ããŒãã³ãã®ç¶æ
ãæå³çã«å€æŽããããšãããŸããªã±ãŒã¹ã®1ã€ã§ãã ãã ããå€æŽãã°ãææ¡ãã addBreadcrumb
ïŒæçµçã«ã¯æ å
ã®setState
ïŒãuseEffect
ã«ã©ãããããšãå®è¡é åºã¯ä¿èšŒãããªããªããŸãã 3ã€ã®setStates
ã¯ãã¹ãŠãã¬ã³ããªã³ã°ãçµäºããåŸã«å®è¡ãããŸããããã«ããã競åç¶æ
ãçºçããã·ã¹ãã ãç ŽæããŸãã
ãã®ç¬ç¹ã®ã·ã¹ãã ãã¢ã³ããã¿ãŒã³ãšèŠãªããããã©ããã¯ããããŸããããç§ã«ã¯ãããçã«ããªã£ãŠãããããåçŽãªä»£æ¿æ段ã¯èŠã€ãããŸããã§ããã
çµè«ãšããŠãç§ã¯ãã®æ°ããèŠåãæè¿ããŸãããç§ãã¡ã«ãšã£ãŠæé©ãªè§£æ±ºçã¯ãããæå¶ããæ¹æ³ããããšæããŸãã ãã¶ãã setState
ãžã®2çªç®ã®ãªãã·ã§ã³ã®ãã©ã¡ãŒã¿ã§ããŸãããã§ãããã
@MeLlamoPablo
å åŒãŸãã¯èŠª/åã®ã¬ã³ããªã³ã°é åºã®ã¬ã³ããªã³ã°åŒã³åºãã«äŸåããããšã¯ãéåžžã«è匱ã«èãããŸãã Reactã¯å®éã«ãããä¿èšŒãããã®ã§ã¯ãããŸããã åäŸã¯äž¡èŠªãªãã§åã¬ã³ããªã³ã°ããããšãã§ããŸãïŒãããŠããããã§ãããïŒããããŠãã®éãåæ§ã§ãã åãé 延ããŠã¬ã³ããªã³ã°ãããå ŽåïŒã³ãŒãåå²ãªã©ïŒããã®ã³ãŒããå£ããŸãã ãŸãã¯ãäžéšã®åãåçã«æ¿å ¥ãŸãã¯åé€ãããå Žåã èšããŸã§ããªããã«ã¹ã±ãŒãã¬ã³ããªã³ã°ãéåžžã«å€ããããããã¯ããã©ãŒãã³ã¹ã®é¢ã§ããªãæªãçµæã«ãªããŸãã
ç§ã¯ããªãã解決ããããšããŠããåé¡ã«å ±æããŸãâå®éãä»æ¥ã®Reactã«ã¯æ £çšçãªè§£æ±ºçããããŸããã ç§ãã¡ã¯ããã«ã€ããŠããã€ãã®ã¢ã€ãã¢ãæã£ãŠããŸãããé©åãªè§£æ±ºçã¯ããªãç°ãªãå¿ èŠããããŸãã åœé¢ã®éããã®åé¿çã¯ãå§ãããŸããã
@gaearon ãããªãã®æŽå¯ã«æè¬ããŸãã 質åã1ã€ãããŸããæåã®ã¬ã³ããªã³ã°ã®é åºã¯ä¿èšŒãããŠããŸããïŒ é©åã«æ©èœããããã«å¿ èŠãªã®ã¯ããã ããªã®ã§ïŒãã¬ããã¯ã©ã ã®é åºããããã°ãåŸç¶ã®ã¬ã³ããªã³ã°ã®é åºã¯æ°ã«ãªããŸããïŒã
æåã®ã¬ã³ããªã³ã°ã®é åºãä¿èšŒãããŠããããšã¯ç§ã«ã¯è«ççã«æããŸãã Reactã¯ã芪ã³ã³ããŒãã³ãã«åãååšããããšãã©ã®ããã«ããŠç¥ãã®ã§ããããã
ã«ã¹ã±ãŒãã¬ã³ããªã³ã°ã®ããã©ãŒãã³ã¹ã«ã€ããŠã¯ãããªãã¯çµ¶å¯Ÿã«æ£ããã§ãã ã·ã¹ãã ãæ¹åããæ¹æ³ãæ¢ããŸãã
@MeLlamoPablo
質åã1ã€ãããŸããæåã®ã¬ã³ããªã³ã°ã®é åºã¯ä¿èšŒãããŠããŸããïŒ é©åã«æ©èœããããã«å¿ èŠãªã®ã¯ããã ããªã®ã§ïŒãã¬ããã¯ã©ã ã®é åºããããã°ãåŸç¶ã®ã¬ã³ããªã³ã°ã®é åºã¯æ°ã«ãªããŸããïŒã
匷ãã¯ãªãã ã»ãšãã©ã®å ŽåãçŸåšã®ããŒãžã§ã³ã®Reactã§æ©èœãããšæããŸãããå°æ¥çã«ã¯å€æŽãããå¯èœæ§ããããŸãã ä»æ¥ã§ãã lazy
ãSuspense
ãªã©ã®æ©èœãšçµã¿åããããšä¿èšŒãããŸããã
Reactã¯ã芪ã³ã³ããŒãã³ãã«åãååšããããšãã©ã®ããã«ããŠç¥ãã®ã§ããããã
å åŒã®é åºã¯ä¿èšŒãããŸããã 芪/åã®é åºã«ã€ããŠã¯ã芪ãæåã«ã¬ã³ããªã³ã°ããå¿ èŠãããã®ã¯æ£ããã§ãã ãã ããReactã¯ãåã«å°éããåããŸãã¯æåã®åãã¬ã³ããªã³ã°ããåŸã2çªç®ã®åã®
ããã¯å£ããããã§ãã
@gaearon ãããããšãã ããã¯éåžžã«ãããããã§ãã
ãããããã¬ã³ããŒããã£å
ã§useState
ãã¥ãŒããŒã¿ãŒãåŒã³åºããªãããã«èŠåããESLintã«ãŒã«ãããã¯ãã§ããïŒ
ã¬ã³ããªã³ã°äžã«ç¬èªã®ã³ã³ããŒãã³ãã®setStateãåŒã³åºãããšã¯ããµããŒããããŠãããã¿ãŒã³ã§ãïŒãã ããæ éã«äœ¿çšããå¿ èŠããããŸãïŒã æªãä»ã®ã³ã³ããŒãã³ãã®setStateã§ãã ããããéçã«æ€åºããããšã¯ã§ããŸããã
çè«çã«ã¯ãts-eslintã䜿çšããŠãæ£ããã¢ããã¹ããªãŒã Reactã¿ã€ãã䜿çšããŠãããšä»®å®ããŠå®è¡ã§ããŸãããããããããã®äŸ¡å€ãããå€ãã®åŽåãå¿ èŠã§ãã
ãªãããã®å¹æ远跡ãªãã§ã¯å®çŸã§ããªããšæããŸãã éäžã«1ã€ã®æ©èœããããšããã«ãæ å ±ã倱ãããŸãã
react@experimental
+react-redux
+redux
ã§ããã®åé¡ã«çŽé¢ããŠããŸããã³ãŒãã¯æ¬¡ã®ããã«ãªããŸãã
import React, { Suspense } from 'react' import { bindActionCreators } from 'redux' import { connect } from 'react-redux' import { Redirect } from 'react-router-dom' import PropTypes from 'prop-types' import { userActions, cabinetActions, tokensActions } from '../../actions' import { CircularProgress } from '@material-ui/core' import { api } from './api' const Cabinet = ({ resource }) => { resource.read() return <h1>cabinet</h1> } Cabinet.propTypes = { resource: PropTypes.shape({ read: PropTypes.func }) } const CabinetPage = ({ failedToLoad, tokensRefreshFailed, logout, loadCabinet, clearTokens, clearCabinet }) => { if (tokensRefreshFailed || failedToLoad) { clearTokens() clearCabinet() logout() return <Redirect to='/login' /> } return ( <Suspense fallback={<CircularProgress />}> <Cabinet resource={loadCabinet()} /> </Suspense> ) } CabinetPage.propTypes = { loadCabinet: PropTypes.func, failedToLoad: PropTypes.bool, tokensRefreshFailed: PropTypes.bool, logout: PropTypes.func, clearTokens: PropTypes.func, clearCabinet: PropTypes.func } const mapStateToProps = ({ alert, tokens: { tokensRefreshFailed }, cabinet: { failedToLoad } }) => ({ alert, tokensRefreshFailed, failedToLoad }) const mapDispatchToProps = dispatch => bindActionCreators( { cabinetLoad: cabinetActions.load, logout: userActions.logoutWithoutRedirect, loadCabinet: api.loadCabinet, clearCabinet: cabinetActions.clear, clearTokens: tokensActions.clear }, dispatch ) export default connect(mapStateToProps, mapDispatchToProps)(CabinetPage)
loadCabinet()
ã¯ãåæããã¥ã¡ã³ããèšãããã«ã3ãã§ãŒãºã¬ã³ããªã³ã°ã®éåæã¢ã¯ã·ã§ã³ããã£ã¹ãããããread()
propã䜿çšããŠãªããžã§ã¯ããè¿ããŸãã
ãã ããããã§ã¯èŠªã®æŽæ°ã確èªã§ããŸããã
ãã®åé¡ãæ±ããŠããä»ã®äººã®ããã«ãè¿ãããã³ã³ããŒãã³ãã«reduxã¢ã¯ã·ã§ã³ãã£ã¹ãããã移åããããšã§ä¿®æ£ããŸããã çŸåšã®æ§åã¯æ¬¡ã®ãšããã§ãã
const CabinetPage = ({
alert,
failedToLoad,
tokensRefreshFailed,
logout,
loadCabinet,
clearTokens,
clearCabinet,
clearAlert
}) => (
<Suspense fallback={<MUIBackdropProgress />}>
{alert.message && (failedToLoad || tokensRefreshFailed) ? (
<MUIAlertDialog
title={alert.message}
text={errorText}
onClose={() => {
clearAlert()
clearCabinet()
clearTokens()
logout()
}}
/>
) : (
<Cabinet resource={loadCabinet()} />
)}
</Suspense>
)
æ£ãããã¶ã€ã³ãã¿ãŒã³ãéžæããå¿ èŠãããããããã®èŠåãæ°ã«å ¥ã£ãŠããŸãã ä»ã§ã¯ãã¹ãŠãå®ç§ã«æ©èœããŸãïŒ
16.13.1ã§èŠåãéå°ã«çºçããã±ãŒã¹ãä¿®æ£ããŸããã æ®ãã®ã±ãŒã¹ã¯æ£åœã§ãããä¿®æ£ããå¿ èŠããããŸãã
@gaearonãã¢ããã°ã¬ãŒãããããšã©ãŒãæ¶ããŸããïŒ çãããããããšãããããŸããïŒ
@gaearonããããšãã ããªãã¯ç§ã®æ¥ãæã£ã:-)
ã¢ããã°ã¬ãŒãããŠãåé¡ã¯è§£æ±ºããŸããã§ããããåé¡ãèŠã€ããã®ã«åœ¹ç«ã€æ å ±ãã³ã³ãœãŒã«ã«è¡šç€ºãããŸããã ããããšã@gaearon ïŒ
ä»ã®ã³ã³ããŒãã³ããååãšåãç¶æ ãè¿ãããã«ããã¢ã¯ã·ã§ã³ããã£ã¹ããããããšã©ããªããŸããïŒ ããã¯æªããšèããããŠããŸããïŒ ãã®å Žåã¯ç絡ãããšæããŸãã
ç§ã¯å®å šã«ãã®èŠåã®èåŸã«ããããžãã¯ãç解ããªãããç§ã¯ãã®ããšãèšãããšãã§ãã...ããã¯ã»ãšãã©ã®ããŒã ãã³ãŒãã«ã©ã®çšåºŠãããã®éèŠãªççãæããŠããããã«ããã¯æããŠããã®ã§ãããŒã ãã³ãã¥ããã£ãèªã£ãŠãããªã¢ã¯ãäœã®è£åãã®ããã«æããŠããŸãåå¿ïŒ
1ïŒéå±€å ã§å¿ èŠãªã ãé«ãç¶æ ïŒãã以äžã§ã¯ãªãïŒãç¶æããŠãããããŒã¿ãšã»ãã¿ãŒãåã³ã³ããŒãã³ãã«æž¡ããŸã
2ïŒé¢æ°ã³ã³ããŒãã³ãã¯çŽ æŽãããã§ãïŒ ãã®ã¯ã©ã¹ã®ãã€ãºãå¿ããŠãã³ã³ããŒãã³ãå šäœã1ã€ã®é¢æ°ã§å®è¡ããŠãã ããïŒ
ãããŠä»ã人ã ããããã®2ã€ã®ã«ãŒã«ã«åŸããç¶æ ã»ãã¿ãŒãé¢æ°ã³ã³ããŒãã³ãã«æž¡ãããããããããã®ã³ã³ããŒãã³ãã§åŒã³åºããšãã©ã°ãåŒãåºããŠããããšèšããŸãããå®éã«ã¯ç§ãã¡ãèšã£ãããšãå®è¡ããããšã¯ã§ããŸãããããããšãã
ããã¯ãããã§ã®æè¡çããŒãºã«ã€ããŠã¯äœãå€æŽããŸããããã®å€æŽã«ã€ããŠäœãééã£ãŠããããŸãã¯æªããšèšã£ãŠããããã§ã¯ãããŸãã...ã¡ãã»ãŒãžã³ã°ã®åé¡ããããšæããŠããŸããã€ãŸãã2ã€ã®ãããªæ確ãªã«ãŒã«ãäŒéããŠããªããšããããšã§ãããã®æ°ããäžçã§ã®ã³ãŒãã£ã³ã°ã«ã€ããŠã¯ãå ã»ã©è§ŠããŸããïŒã ã«ãŒã«ãå€æŽããå Žåã¯ãæåã«ãã¹ããã©ã¯ãã£ã¹ã説æããããšã§å€æŽãããšåœ¹ç«ã€ãšæããŸãã
ã§ããããç§ãæ¬åœã«æ±ããŠããã®ã¯...ããŒã ã®èª°ããïŒèšäºã®ããã«ïŒäœããæžããšãããããã£ãšçæ³çã ãšæããŸããæ°ããã«ãŒã«ããã¯ãªãã¯ãããã®æ°ããèŠåãåç §ããããã¥ã¡ã³ã/ãªãªãŒã¹ããŒãã®ãã¹ãŠã®å Žæã«ãã®èšäºãžã®ãªã³ã¯ãè¿œå ããŸãïŒãããã£ãŠããWTFã¯ããã§ããïŒããã°ãŒã°ã«ã§æ€çŽ¢ãããã¹ãŠã®äººãããæ°ããã«ãŒã«ãã§Reactãã³ãŒãã£ã³ã°ããé©åãªæ¹æ³ãåŠã¶ããšãã§ããŸãäžç"ïŒã
@machineghost ïŒã¡ãã»ãŒãžãäœã«ã€ããŠèŠåããŠããã®ã誀解ããŠãããšæããŸãã
芪ã®ç¶æ ãæŽæ°ããã³ãŒã«ããã¯ãåã«æž¡ãããšã«ã¯äœã®åé¡ããããŸããã ããã¯ãã€ã倧äžå€«ã§ãã
åé¡ã¯ãããã³ã³ããŒãã³ããå¥ã®ã³ã³ããŒãã³ãã®æŽæ°ããã¥ãŒã«å ¥ããŠãããšãã«ã_æåã®ã³ã³ããŒãã³ããã¬ã³ããªã³ã°ãããŠããé_ã§ãã
èšãæããã°ããããè¡ããªãã§ãã ããïŒ
function SomeChildComponent(props) {
props.updateSomething();
return <div />
}
ããããããã¯åé¡ãããŸããã
function SomeChildComponent(props) {
// or make a callback click handler and call it in there
return <button onClick={props.updateSomething}>Click Me</button>
}
ãŸããDanãäœåºŠãææããŠããããã«ãã¬ã³ããªã³ã°äžã«_same_ã³ã³ããŒãã³ãã®æŽæ°ããã¥ãŒã«å ¥ããããšãåé¡ãããŸããã
function SomeChildComponent(props) {
const [number, setNumber] = useState(0);
if(props.someValue > 10 && number < 5) {
// queue an update while rendering, equivalent to getDerivedStateFromProps
setNumber(42);
}
return <div>{number}</div>
}
ããã§ãããã³ã³ããŒãã³ããã³ãŒãã£ã³ã°ããŠãããšãã¯ããã®èŠªã®ã¿ã€ãã³ã°ã«ã€ããŠã¯èããŠããŸããã ããã¯ãReactã³ã³ããŒãã³ãã®çŸããã®äžéšã§ããã«ãã»ã«åã§ãã
ç¹°ãè¿ãã«ãªããŸãããæ°ããèŠåããŸã£ããæªããšèšã£ãŠããã®ã§ã¯ãããŸãããè¯ãReactéçºè ãåŸãããšãã§ãã2ã€ã®ã«ãŒã«ãã§ããåã«èšã£ãŠããŸãã Xã®æ¡ä»¶äžã§ã¯ããããã®ã«ãŒã«ã¯ãŠã£ã³ããŠã®å€ã«åºãŸãããXã®äžã§ã®ã¿ã§ãïŒX =ã芪ã³ã³ããŒãã³ããæŽæ°äžãã®ããã«èãããŸãïŒã
ãããã¯ä»åé¡ã ïŒããšããã ãã§ãªããããã説æããåé¡ãåé¿ããæ¹æ³ã«ãã£ãšçŠç¹ãåœãŠãå¿ èŠããããšæããŸãã
@machineghost ïŒããªãã¯ç§ãããã§èšã£ãŠããããšã_æ¬åœã«_åŸãŠããŸããã
芪åã®ã¿ã€ãã³ã°ã¯åé¡ã§ã¯ãããŸããã
é¢æ°componentã®ã¬ã³ããªã³ã°äžã«ä»ã®ã³ã³ããŒãã³ãã®ç¶æ æŽæ°ããã¥ãŒã«å ¥ããããšãåé¡ã§ãã
å®çŸ©äžãããã¯èŠª/åïŒãŸãã¯å«ïŒã§ãªããã°ãªããŸããïŒä»ã«ã©ã®ããã«ããŠç¶æ èšå®è ãåŒãç¶ãããšãã§ããã§ããããïŒ
ãããä»ã®ã³ã³ããŒãã³ãã®é¢ä¿ã§ãåé¡ã«ãªãããšã¯ãªããšèšã£ãŠããããã§ã¯ãããŸããããReactã®ãã¹ããã©ã¯ãã£ã¹ã«åŸããç¶æ èšå®è ãåŒãç¶ãã§ããã®èŠåãåãåã人ã ã«ã€ããŠå ·äœçã«è©±ããŸãã
ç§ã話ããŠããã®ã¯ããã ãã§ãããç§ãèšã£ãŠããã®ã¯ãããããæ°ãããšã©ãŒã§ããããããäœãæå³ããã®ãããšããã ãã§ãªããããŸãã³ãŒãã£ã³ã°ããæ¹æ³ã«çŠç¹ãåœãŠãããšã§ããããã説æã§ãããšããããšã§ãã
ã¿ã€ãã³ã°ã ãããã åé¡ã
é¢æ°ã³ã³ããŒãã³ãã¯ãã¬ã³ããªã³ã°äžã«ãããèªäœã«å¯ŸããŠã®ã¿ç¶æ
æŽæ°ããã¥ãŒã«å
¥ããããšãã§ããŸãã ç§ã®äŸã瀺ããããã«ãããã¯getDerivedStateFromProps
ãšåçã«æ©èœããŸãã
é¢æ°ã³ã³ããŒãã³ãã®å®éã®ã¬ã³ããªã³ã°æ¬äœå ããä»ã®ã³ã³ããŒãã³ãã®æŽæ°ããã¥ãŒã«å ¥ããããšã¯éæ³ã§ãã
ããããã®èŠåãããªãã«äŒããŠããããšã§ãã
ããããã£ãšæ確ã«èª¬æããæ¹æ³ãããããŸããã
ã¿ã€ãã³ã°ã¯åé¡ã§ã¯ãããŸããïŒããªãã®ãã®ã§ã¯ãªããç§ã®ãã®ã§ããããŸããã ç§ã®åé¡ã¯ããã¥ã¡ã³ãããŸãã¯ãã®æ¬ åŠã§ãã
ããããããªãã¯åœŒããèšã£ãŠããããšã«è³ãåŸããã®ã§ã¯ãªããã€ã³ã¿ãŒãããã®èŠç¥ãã¬äººãšã®åé¡ã¹ã¬ããã§æŠäºãå§ããããšã«æ±ºããŸãã...ç§ã¯ããªããšé¢ããç¶ããããšãæãã§ããŸããã
éèŠãªã®ã¯ãã«ãŒã«ãå€æŽãããŠããªããšããããšã§ãã ããã¯åžžã«ééã£ããã¿ãŒã³ã§ããã ã³ãŒãã«ãã°ãããããšã«æ°ä»ãããã«ããã€ã©ã€ã衚瀺ãããŠããŸãã
ãããŠãæåéããããªããä»èšã£ãããšã¯ãç§ãæžãããã®ãšççŸãããã®ã¯äœããããŸããã å®éãããã¯ç§ãæåãããŸã£ããåãããšãèšã£ãããã§ã...ãããŠç§ããããŸã§ãã£ãšæ±ããã®ã¯ãããã®åãã«ãŒã«ã®ããè¯ã説æã§ãããããªããèšããã®ã¯å€ãã£ãŠããŸããïŒãããŠãã¡ãã圌ãã¯ããŠããŸãã...äœãå€ãã£ãŠãæ°ããäžçãäœã£ããã®ããèŠåã§ããïŒã
PSããªããããã§ç®èã«æ°ã¥ããŠããªãããã§ãã ç§ãäœãç解ã§ããªãå Žåãããã¯ããã¥ã¡ã³ããæ¹åãããå¯èœæ§ããããšããããšã§ãã ç§ãç©äºãã©ãã»ã©ããç解ããŠããªããã«ã€ããŠç§ã«æ鳎ãããšã¯ãç§ã®ç«å Žã匷ããã ãã§ãã ããã¥ã¡ã³ããéæ³ã®ããã«æ¹åããããšã¯ãããŸããã
ããã«ã¡ã¯çãããå°ãã¯ãŒã«ããŠã³ããŸãããã ð
@markeriksonåå ããŠããã ãããããšãããããŸããããã®è°è«ã¯å°ãç±ããªããããŠãããšæããŸãã
@machineghostæžå¿µãè¡šæããŠããã ãããããšãããããŸãã 以åã¯ç¡å®³ã«èŠãããããããªããã¿ãŒã³ã«å¯ŸããŠæ°ããèŠåããããã¢ããããã®ã¯è¿·æã ãšç§ã¯ç¥ã£ãŠããŸãã
ãã®èŠåã«ã¯äºåã®ã³ã³ããã¹ããå¿ èŠã§ããããšã«åæããŸãã åºæ¬çã«ãã¯ã©ã¹ã®æ代ãã2ã€ã®ããšãç¥ãå¿ èŠããããŸããã
ã¬ã³ããªã³ã°äžã«SetStateã䜿çšããªãã§ãã ããã ã¯ã©ã¹ã¯åžžã«ããã«ã€ããŠèŠåããŸããã
ãã®é¢æ°ã³ã³ããŒãã³ãæ¬äœã¯ãåºæ¬çã«ã¯ã©ã¹ã³ã³ããŒãã³ãã®renderã¡ãœãããšåããã®ã§ãã
é¢æ°ã³ã³ããŒãã³ãæ¬äœã®éã«å¥ã®ã³ã³ããŒãã³ãã®setStateã以åã«èŠåããªãã£ãã®ã¯ã確ãã«ç§ãã¡ã®çç¥ã§ãã äžèšã®2ã€ã®ãã€ã³ãããæªããã¿ãŒã³ã§ãããšæšæž¬ã§ããŸã
ããã¥ã¡ã³ãå ã§ããã«ã€ããŠèšåããå¿ èŠãããç¹å®ã®å Žæããããšæãããå Žåã¯ãããã¥ã¡ã³ããªããžããªã§åé¡ãæèµ·ããŠãã ããã ããã¯ã«åºã¥ããŠããã¥ã¡ã³ããæžãçŽãããšãèšç»ããŠããã®ã§ããããèŠããŠããããšãã§ããŸãã ããããšãïŒ
ç§ã¯æ±ºããŠèª°ãã«äœãã«ã€ããŠæ°åã害ãããã€ããã¯ãããŸããããããŠç§ã¯ããªãã®è¬çœªãåãå ¥ããããšãæåŠããŸã;ïŒããã¯ã¯å€©æã§ããããããŠããªãã¯ããããçºæããããã®å€©æã§ãã ãããŠããã¹ãŠã®çµæãå®å šã«æ³åããŠããªãã£ãããã«å¥ã®ãšã³ãžãã¢ã責ãããšã³ãžãã¢ã¯èª°ã§ã...ãžã£ãŒã¯ã§ãã
ç§ãäŒããããšããŠããã®ã¯ãçŸåšããã®èŠåãåãåã£ããšããç§ã¯ã¿ããªãããŠããããšãããŸããïŒç§ã¯ãããã°ãŒã°ã«ã§æ€çŽ¢ããŸããã 次ã«ãããã®æ°ããèŠåããããŸãããšããããŒãžãèŠã€ããŸããã
ãã®ã¢ããŠã³ã¹ããŸãã¯èª°ããã°ãŒã°ã«ã§èŠã€ãããããããªãåæ§ã®å Žæã«ããããã«ãããªããã®ãšã©ãŒãçºçããã®ãããããŠãããããªããçŽ æŽãããReactéçºè ã«ãªããèªåã§ééããªãããã«ããã€ãã®åºæ¬çãªã¬ã€ãã©ã€ã³ã«åŸãæ¹æ³ã§ããã
ããããç¹°ãè¿ãã«ãªããŸãããããã¯ã¯çŽ æŽããããReactããŒã ã¯çŽ æŽãããããã®æ°ããèŠåã§ããçŽ æŽããããªããŸãïŒé²åŸ¡ããããšããŠãããšã©ãŒãçºèŠããããšã§ãããã¯å°çãæã¡è² ãããšç¢ºä¿¡ããŠããŸãïŒã 誰ãã誰ãã«è¬çœªãã矩åããããªãããããå å°ããªãã£ãã®ã¯ç§ã§ãã
確ãã«ãé£ããææ ã¯ãããŸããã ãçç±ãã®çãã¯ããã¬ã³ããªã³ã°äžã«1ã€ã®ã³ã³ããŒãã³ããä»ã®ã³ã³ããŒãã³ãã®æŽæ°ãããªã¬ãŒãããšãã¢ããªã®ããŒã¿ãããŒããããããŠã³ã§ãªããªãããã远跡ãéåžžã«å°é£ã«ãªãããããè€éã§ã¯ãããŸããã ãããã£ãŠããããããšãReactã®ã¡ãªãããæšãŠãŠããŸãããšã«ãªããŸãã
ç¹°ãè¿ããŸãããæ確ã«ããããã«ãããèªäœã¯æ°ãããã®ã§ã¯ãããŸãããã¯ã©ã¹ã«ã¯åžžã«åãèŠåããããŸããã ç§ãã¡ã¯ããã¯ã§ãããèŠéããééããä¿®æ£ããŠããŸãã ä¿®æ£æ¹æ³ã¯ã±ãŒã¹ã«ãã£ãŠç°ãªããšæããŸãããæ£ç¢ºãªæé ã説æããããšã¯ã§ããŸããããèŠåŽããŠããäŸãå ±æããŠããã ããã°å¹žãã§ãã äžè¬çã«èšã£ãŠãåžžã«ååšããŠãã察å¿ããã¯ã©ã¹ã®èŠåãä¿®æ£ããã®ãšåãæ¹æ³ã§ä¿®æ£ããŸãã
ããããããã圹ç«ã€ããšãé¡ã£ãŠããŸãïŒ
ç§ã¯ãã®è°è«ã«ç§ã®2ã»ã³ããè¿œå ããæ©èœã³ã³ããŒãã³ããšããã¯ã®å°å ¥ä»¥æ¥å€ãã®æ··ä¹±ããã£ããšãã@machineghostã«åæããŸãã ã³ãã¥ããã£ã¯ãªãŒããŒã·ãããæ±ããŠãªã¢ã¯ã·ã§ã³ããŒã ãæ¢ããŠããŸããã以åã¯åçŽã ã£ããã®ãè€éã«ãªããã³ãã¥ãã±ãŒã·ã§ã³ãšæ確ãªäŸãäžè¶³ããŠããããã§ãã
ã±ãŒã¹ãšãã€ã³ãã¯ComponentDidMountãšUnmountã§ãããæåã«é¢æ°ã³ã³ããŒãã³ãã䜿çšããããã«æ瀺ããã次ã«ç©ºã®é åã§useEffectã䜿çšããããã«æ瀺ããã次ã«ããã¯è¯ããªããšèšãããä»ã§ã¯ãã®ãšã©ãŒã¡ãã»ãŒãžãæ··ä¹±ããŠããŸãã ããããŸããããã¹ãŠã®ããŒãã¯ãŒã¯ãåå¿ããããšã«æè¬ããŠããŸãããããã¥ã¡ã³ããšãã¹ããã©ã¯ãã£ã¹ã«ãã£ãšåãå ¥ããå¿ èŠããããŸãã
ç§ã¯é·ãéé¢æ°ã®ææµã«ä¹ã£ãŠããã®ã§ïŒããã¯ã®åã§ãRecomposeãªã©ã®ã¯ã©ã¹ãé¿ããããšããŠããŸãïŒããããã®ã¯ã©ã¹ã®èŠåããèŠããŠããŸããã
ãããŠãããªãã®åçã«æè¬ããŸãããç§ã¯äž»ã«ãçµéšåããã¬ã€ãã©ã€ã³ããã¹ããã©ã¯ãã£ã¹ãªã©ãæãã§ããŸããã "ãŸãã¯"å¶åŸ¡ãã¿ãŒã³ã®å転ã䜿çšããŠç¶æ ã»ãã¿ãŒãåã³ã³ããŒãã³ãã«æž¡ããŸã "ã
ããã«ã¯äœããªããããããŸãããããæ©èœã³ã³ããŒãã³ãAãç¶æ ãå€æŽããå Žåãç¶æ ã»ãã¿ãŒãæž¡ãåã³ã³ããŒãã³ãBãã¬ã³ããªã³ã°ããã¹ãã§ã¯ãããŸããïŒããã«æ»ãå¿ èŠããããŸãïŒãåã³ã³ããŒãã³ãã¯ãåé¡ãçºçããç¶æ ãã¬ã³ããªã³ã°ããã³å€æŽããŸããã
ãããã¯ãæ¥ææ¥ã®é ãæéã«ãç§ã¯äžæ¥äžå人çãªãããžã§ã¯ãã«åãçµãã§ããŠãç§ã®è³ã¯ããŸãã«ãæããããŠãåçŽãªãã®ãé£ãããã®ã«å€ããŠããŸãã ãããã«ãããã¬ã€ãã©ã€ã³ã«ã€ããŠããã«ææ¡ãããã°æçš¿ããŸããããã以å€ã®å Žåã¯ãä»ã®èª°ããæ¥ææ¥ã®å€ãããã«è²»ãããããªãããšã¯ç¢ºãã§ãã
ã§ãããããšãïŒ
ãã®ã¹ã¬ããããã®æçšæ§ãè¶ ãããšãããŸã§æ¥ãŠãããšæããŸãã
ã±ãŒã¹ãšãã€ã³ãã¯ComponentDidMountãšUnmountã§ãããæåã«é¢æ°ã³ã³ããŒãã³ãã䜿çšããããã«æ瀺ããã次ã«ç©ºã®é åã§useEffectã䜿çšããããã«æ瀺ããã次ã«ããã¯è¯ããªããšèšãããä»ã§ã¯ãã®ãšã©ãŒã¡ãã»ãŒãžãæ··ä¹±ããŠããŸãã
ç§ãã¡ã®ããã¥ã¡ã³ãã圹ã«ç«ããªãã£ãããšããè©«ã³ããŸãããããªããééããç¹å®ã®åé¡ãèšãã®ã¯éåžžã«é£ããã§ãã ããã¯æ®å¿µãªããéåžžã«ææ§ã§ãããç§ãã¡ãèšãããšããããšã®ããã¿ã§ãã å£ããé»è©±ã®ã²ãŒã ã®ããã«ã ç¹å®ã®åé¡ãããå Žåã¯ãæ°ããåé¡ãæåºããŠããã詳现ã«èª¬æããŠãã ããã ããªããããå ·äœçã«ããããšãã§ãããªãã°ãæã ã¯ããªããå©ããããã«åªããŸãã
ãããŠãããªãã®åçã«æè¬ããŸãããç§ã¯äž»ã«ãçµéšåããã¬ã€ãã©ã€ã³ããã¹ããã©ã¯ãã£ã¹ãªã©ãæãã§ããŸããã
çµéšåã¯åžžã«ãã¬ã³ããªã³ã°äžã«å¯äœçšãå®è¡ããªããã§ããã ã¬ã³ããªã³ã°ãçŽç²ãªèšç®ãšèããŠãã ããã å¯äœçšã¯å¥ã®å Žæã«çºçããŸãïŒã¯ã©ã¹ã®ã©ã€ããµã€ã¯ã«ã¡ãœããããŸãã¯é¢æ°ã³ã³ããŒãã³ãã®useEffectïŒã ãã以äžã®ãã®ã¯ãããŸããã
ãæ©èœã³ã³ããŒãã³ãAãç¶æ ãå€æŽããå Žåãç¶æ ã»ãã¿ãŒãæž¡ãåã³ã³ããŒãã³ãBãã¬ã³ããªã³ã°ããªãã§ãã ããïŒããã«æ»ãå¿ èŠããããŸãïŒãåã³ã³ããŒãã³ããã¬ã³ããªã³ã°ããŠç¶æ ãå€æŽãããšãåé¡ãçºçããããã§ããã
ããã«ã¯ãŸã 誀解ããããšæããŸãã ç¶æ ã»ãã¿ãŒãåã³ã³ããŒãã³ãã«æž¡ãããšã¯ãŸã£ããåé¡ãããŸããã ãã€ãå æ°ã§ãããããããããªãã§ãããã
åé¡ã¯ãã¬ã³ããªã³ã°äžã«ããããåŒã³åºãããšã§ãã ããã¯äžè¬çã«å®å šã«äžèŠãªã¯ãã§ãã å ·äœçãªäŸããªããã°ããªãããããŠããã®ãæšæž¬ããã®ã¯é£ããã§ãã ã§ããããå©ããã®ã¯é£ããã§ãã
ãããã®äŒè©±ã®äž¡æ¹ã®äžè¬çãªããŒãã¯ãç§ãã¡ã茪ã«ãªã£ãŠè¡ããšããããšã§ãã è°è«ã¯ã¡ã¿ã«åãæ¿ãããç¹å®ã®ã±ãŒã¹ã«ã€ããŠè©±ã代ããã«ãæŒ ç¶ãšããäžè¬æ§ã«ã€ããŠè°è«ããŠããŸãã ç§ãã¡ã¯ãäºãã誀解ããŠããå¯èœæ§ããããŸãããå ·äœçãªäŸããªãããããã®èª€è§£ã解決ããããšã¯äžå¯èœã§ãã
ãã®ããããã®ã¹ã¬ãããããã¯ããŸãã ããã§ã®çããã®ãæèŠã«æè¬ããŸãããã®èŠåãä¿®æ£ããã®ã«èŠåŽããŠããå Žåã¯ããã²ãæèŠããèãããã ããã ãã«ããåŸãæ¹æ³ã¯ãæå°éã®åçŸäŸã§åé¡ãæåºããããšã§ãã 次ã«ãå ·äœçãªåé¡ã«ã€ããŠè©±ãåãã解決çã®ãã¬ã€ã³ã¹ããŒãã³ã°ãæ¯æŽããŸãã ããã«ãããé¢ä¿ãããã¹ãŠã®äººã«ãšã£ãŠããçç£çã«ãªãããã®ã¹ã¬ããã«ãã§ã«ã³ã¡ã³ãããŠè³Œèªããããšã«ãªã£ãäœå人ãã®äººã ã«é»åã¡ãŒã«ãéä¿¡ããããšãåé¿ãããŸãã ããããšãããããŸããïŒ
å°ããªæŽæ°ãšããŠïŒå šå¡ã«pingãéä¿¡ããŠç³ãèš³ãããŸããïŒã httpsïŒ //github.com/final-form/react-final-form/issues/751#issuecomment-606212893ãããã䜿çšããŠãã人ã ã®ãããã®ãšã©ãŒã®æã解決ãããšèããŸããå³æžé€šã
æãåèã«ãªãã³ã¡ã³ã
å°æ¥ã®ã³ã¡ã³ããŒã¿ãŒãžã æ°ããèŠåãèŠãã®ã¯ã€ã©ã€ã©ããããšãç解ããŠããŸãã ããããããã¯ããªãã®ã³ãŒãã«ãã°ãåŒãèµ·ãããŠãŠããŸãã ç®èãç ©ãããã®è¡šçŸããé æ ®ããã ããã°å¹žãã§ãã
ã¹ã¿ãã¯ãã¬ãŒã¹ã®ã©ãããæ¥ãŠããã®ãããããªãå Žåã¯ãã¹ã¯ãªãŒã³ã·ã§ãããæçš¿ããããåçŸãµã³ãããã¯ã¹ãäœæããŠãã ããããµããŒããããŠããã ããŸãã ãããã®ã»ãšãã©ã¯ããããããã€ãã®ã©ã€ãã©ãªããã®ãã®ã§ãããããæãçç£çãªæ¹æ³ã¯ããããã®ã±ãŒã¹ãæžãããŠããããããã®ã©ã€ãã©ãªã§åé¡ãå ±åããããšã§ãã
çãããããããšãããããŸããã