ããã«ã¡ã¯ãç§ã®ååã¯Sergeyã§ããWebäžã®ã³ã³ããŒãã³ããåå©çšããåé¡ã«èå³ããããŸãã 圌ããã©ã®ããã« SOLIDãåå¿ã«é©çšããããšããŠããã®ããèŠãŠãç§ã¯ãã®ãããã¯ãç¶ç¶ãã äŸåæ§æ³šå ¥ãŸãã¯DIã®ã¢ã€ãã¢ãéçºããããšã§ã©ã®ããã«è¯å¥œãªåå©çšãéæã§ãããã瀺ãããšã«ããŸããã
Webã®ãã¬ãŒã ã¯ãŒã¯ãæ§ç¯ããããã®åºç€ãšããŠã®DIã¯ãããªãæ°ããã¢ãããŒãã§ãã å±æ©ã«whatããŠãããã®ãæ確ã«ããããã«ããªã¢ã¯ã·ã§ã³éçºè åãã®éåžžã®ããšããå§ããŸãã
ã³ã³ããã¹ãããDIãž
Reactãæäœãããšãã«ãå€ãã®äººãã³ã³ããã¹ãã䜿çšãããšç¢ºä¿¡ããŠããŸãã çŽæ¥ã§ã¯ãªãå Žåãããããreduxã§æ¥ç¶ããããmobx-reactã§æ³šå ¥ããŸãã äžçªäžã®è¡ã¯ãããã³ã³ããŒãã³ãïŒMessageListïŒã§ã³ã³ããã¹ãã§äœãã宣èšããå¥ã®ã³ã³ããŒãã³ãïŒãã¿ã³ïŒã§ãã®äœããã³ã³ããã¹ãããå€ããããšããããšã§ãã
const PropTypes = require('prop-types'); const Button = ({children}, context) => <button style={{background: context.color}}> {children} </button>; Button.contextTypes = {color: PropTypes.string}; class MessageList extends React.Component { getChildContext() { return {color: "purple"}; } render() { return <Button>Ok</Button>; } }
ããªã㡠芪ã³ã³ããŒãã³ãã«äžåºŠcontext.color
ãèšå®ããããšãcontextTypesãä»ããŠè²ãžã®äŸåã宣èšãããŠãããã¹ãŠã®åºæ¬ã³ã³ããŒãã³ãã«èªåçã«è»¢éãããŸãã ãããã£ãŠãéå±€å
ã®ããããã£ãã¹ã¯ããŒã«ããã«ãã¿ã³ãã«ã¹ã¿ãã€ãºã§ããŸãã ããã«ãéå±€ã®ã©ã®ã¬ãã«ã§ãã getChildContext() ...
ããã¹ãŠã®åã³ã³ããŒãã³ãã®è²ãåå®çŸ©ã§ããŸãã
ãã®ã¢ãããŒãã«ãããã³ã³ããŒãã³ããçžäºã«åé¢ãããæ§æãšåå©çšãç°¡çŽ åãããŸãã äžèšã®äŸã§ã¯ã芪ã³ã³ããŒãã³ãã§è²ãå®çŸ©ããã ãã§ååã§ããã¹ãŠã®ãã¿ã³ã®è²ãå€ãããŸãã ããã«ãButtonã³ã³ããŒãã³ãã¯å¥ã®ã©ã€ãã©ãªã«ããå Žåãããããªãã¡ã¯ã¿ãªã³ã°ããå¿ èŠã¯ãããŸããã
ããããåå¿ã«ã€ããŠã¯ãææ ®æ·±ããäžååã§ããããããã®ã¢ãããŒãã¯ãŸã ååã«éçºãããŠããŸããã éçºè ã¯ãçŽæ¥äœ¿çšããããšããå§ãããŸããã
ããã¯å®éšçãªAPIã§ãããReactã®å°æ¥ã®ãªãªãŒã¹ã§æ©èœããªããªãå¯èœæ§ããããŸã
ããã¥ã¡ã³ãã«æžãããŠããŸãã çŸåšããªãã®æéãçŸåšã®åœ¢ã§å®éšçã§ãããéçºãåæ¢ãããšããæèŠããããŸãã ã³ã³ããŒãã³ãã®ã³ã³ããã¹ãã¯ãã€ã³ãã©ã¹ãã©ã¯ãã£ïŒgetChildContextïŒã«ãªã³ã¯ãããŠãããPropTypesãä»ããŠç䌌åä»ãããã ã¢ã³ããã¿ãŒã³ãèæ ®ãããµãŒãã¹ãã±ãŒã¿ãŒã«äŒŒãŠããŸã ã ç§ã®æèŠã§ã¯ãã³ã³ããã¹ãã®åœ¹å²ã¯éå°è©äŸ¡ãããŠãããåå¿ã§ã¯äºæ¬¡çã§ãïŒ ããŒã«ãªãŒãŒã·ã§ã³ãšãã åãããã³ reduxãmobxãªã©ã®ã©ã€ãã©ãªãžã®ãã€ã³ãã
ä»ã®ãã¬ãŒã ã¯ãŒã¯ã§ã¯ãåæ§ã®ããŒã«ãããé©åã«éçºãããŠããŸãã ããšãã°ãvueïŒ provide / injectã§ãangularã§ã¯ããã®è§åºŠdiã¯ãã§ã«typescriptåãµããŒããåããæ¬æ Œçãªãã¡ã³ã·ãŒDIã§ãã å®éã2çªç®ã®ããŒãžã§ã³ã®Angularããå§ããŠãéçºè ã¯ããã³ããšã³ãã«é¢ããŠããã¯ãšã³ããšã¯ã¹ããªãšã³ã¹ïŒDIãé·ãéååšããŠããå ŽæïŒãåèããããšããŸããã ããããåå¿ãšãã®ã¯ããŒã³ã«ã€ããŠåæ§ã®ã¢ã€ãã¢ãéçºããããšãããšãã©ã®ãããªåé¡ã解決ãããŸããïŒ
æã¡è² ããããããã¯è³ªåã§ã
æ¬æ Œçãªåå¿/ãªãã¥ãŒã¹ã¢ããªã±ãŒã·ã§ã³ã§ã¯ããã¹ãŠããªãã¥ãŒã¹ã¢ã¯ã·ã§ã³ã«ãã£ãŠå®è¡ãããããã§ã¯ãããŸããã éèŠã§ãªããã§ãã¯ããŒã¯ã®ç¶æ ã¯ãsetStateã䜿çšããŠå®è£ ããæ¹ã䟿å©ã§ãã çµå±ã®ãšãããreduxã䜿çšããã®ã¯é¢åã§ãããsetStateã䜿çšããããšã¯æ®éçã§ã¯ãªããåçŽã§ãã 圌ã¯åžžã«æå ã«ããŸãã æåãªèè ã«ãããReduxãå¿ èŠãšããªããããããªãããšããèšäºã¯ããã¹ã±ãŒãªã³ã°ããå¿ èŠããªãå Žåã¯reduxã䜿çšããªãã§ãã ããããšèšã£ãŠããããã®äºéæ§ã確èªããŠããŸãã åé¡ã¯ãããã¯çŸåšå¿ èŠã§ã¯ãªãããšã§ãããææ¥ã¯ãã§ãã¯ç¶æ ã®ãã°èšé²ãåºå®ããå¿ èŠããããããããŸããã
åãèè ã®Presentational and Container Componentsã«ããå¥ã®èšäºã§ã¯ãããã¹ãŠã®ã³ã³ããŒãã³ãã¯çããïŒPresentationalïŒããäžéšã¯ããçããïŒContainerïŒããšèšãããåæã«è±åŽå²©ã«å»ãŸããŠããŸãïŒreduxãmobxãrelayãsetStateã«éä»ãïŒã Containerã³ã³ããŒãã³ãã®ã«ã¹ã¿ãã€ãºã¯è€éã§ããåå©çšããããšãç®çãšããŠãããããã§ã«ç¶æ ã®å®è£ ãšã³ã³ããã¹ãã«åãããããŠããŸãã
Container-componentsã®äœæãäœããã®æ¹æ³ã§åçŽåããããã«ããããã¯HOCãæãä»ããŸããããå®éã«ã¯ã»ãšãã©å€æŽãããŠããŸããã 圌ãã¯åã«ãæ¥ç¶/æ³šå ¥ãä»ããŠçŽç²ãªã³ã³ããŒãã³ããšreduxãmobxãrelayãªã©ãçµã¿åãããããã«ãªããŸããã ãããŠãçµæã®ã¢ããªã·ãã¯ã³ã³ãããã³ãŒãã§äœ¿çšããŸãã
èšãæããã°ããã¬ãŒã³ããŒã·ã§ã³ãšã³ã³ãããèšããŸãããåå©çšå¯èœãšåå©çšäžå¯èœãæå³ããŸãã æåã¯ã«ã¹ã¿ãã€ãºããã®ã«äŸ¿å©ã§ã ããããã£å ã®ãã¹ãŠã®æ¡åŒµãã€ã³ããããã³2çªç®-ãªãã¡ã¯ã¿ãªã³ã°ãç¶æ ãšããã€ãã®ããžãã¯ã«ãã¹ããããŠãããããããããã£ãå°ãªãããã§ãã ããã¯ã2ã€ã®çžåããåé¡ã解決ããããã®äžçš®ã®åŠ¥åã§ãããã®ä»£åã¯ãã³ã³ããŒãã³ãã2ã€ã®ã¿ã€ãã«åé¢ãã ãªãŒãã³æ§/ã¯ããŒãºæ§ã®ååãç ç²ã«ããããšã§ãã
ããšãã°ãèšäºã Replace and Conquer-the SOLID approach ãã®ããã«ãã»ãšãã©ã®ã³ã³ããŒãã³ããå¯èœãªéãåçŽã«ããæŽåæ§ãæªåãããããšãææ¡ãããŠããŸãã ããããåçŽãªãã®ããè€éãªã³ã³ããŒãã³ããã©ããã§çµã¿ç«ãŠãå¿ èŠããããåæã«ããããã«ã¹ã¿ãã€ãºããæ¹æ³ã«ã€ããŠã®çåãæ®ããŸãã ããªãã¡ åé¡ã¯å¥ã®ã¬ãã«ã«æã¡è¶ãããŸãã
<ModalBackdrop onClick={() => this.setState({ dialogOpen: false })} /> <ModalDialog open={this.state.dialogOpen} > <ModalDialogBox> <ModalDialogHeaderBox> <ModalDialogCloseButton onClick={() => this.setState({ dialogOpen: false })} /> <ModalDialogHeader>Dialog header</ModalDialogHeader> </ModalDialogHeaderBox> <ModalDialogContent>Some content</ModalDialogContent> <ModalDialogButtonPanel> <Button onClick={() => this.setState({ dialogOpen: false })} key="cancel"> {resources.Navigator_ButtonClose} </Button> <Button disabled={!this.state.directoryDialogSelectedValue} onClick={this.onDirectoryDialogSelectButtonClick} key="ok"> {resources.Navigator_ButtonSelect} </Button> </ModalDialogButtonPanel> </ModalDialogBox> </ModalDialog> </ModalBackdrop>
ããã§ããããã®ç«¯æ«ã³ã³ããŒãã³ããã«ã¹ã¿ãã€ãºããªãããšã«åæããå Žåãå®éã«ã¯å€æ°ã®ãã€ã©ãŒãã¬ãŒãã³ãŒããååŸããŸãã1ã€ã®Buttonã眮ãæããããã«ãã³ã³ããŒãã³ãå šäœãåæ§ç¯ãããŸãã ãã®ã¢ãããŒãã§ã¯ãæ¬æ Œçãªãœãªããã¯äžå¯èœã§ãã å€æŽããã«æ¡åŒµã§ããªãç¶æ ãžã®ã³ã³ããŒãã³ããã€ã³ããŒãšãå éšã®ããžãã¯ã®ãªãã³ã³ããŒãã³ãã³ã³ããŒãã³ãã¯åžžã«ååšããããã¯äœ¿çšãå°é£ã§ãã
è©Šäœæ©
äŸåæ§æ³šå ¥ã®ã¢ã€ãã¢ãéçºãããšããããã®åé¡ã®ããã€ãã解決ã§ããŸãã ãã®äŸã«åºã¥ããŠãœãªã¥ãŒã·ã§ã³ãåæããŸãããã
// @flow // @jsx lom_h // setup... class HelloService { @mem name = '' } function HelloView(props: {greet: string}, service: HelloService) { return <div> {props.greet}, {service.name} <br/><input value={service.name} onChange={(e) => { service.name = e.target.value }} /> </div> } // HelloView.deps = [HelloService] ReactDOM.render(<HelloView greet="Hello"/>, document.getElementById('mount'))
é¢æ°ã®ç¶æ
ã«ã¯ãç¶æ
ã§æ©èœãããã©ããã«é¢ä¿ãªãã1ã€ã®æ±çšã³ã³ããŒãã³ã圢åŒããããŸãã ã³ã³ããã¹ãã¯åã䜿çšããŸãã babel-plugin-transform-metadataã䜿çšããŠãäŸåé¢ä¿ã®èª¬æãèªåçã«çæãããŸãã ãã ãããããè¡ãã¿ã€ãã¹ã¯ãªããã«äŒŒãŠããŸãããã¯ã©ã¹ã«å¯ŸããŠã®ã¿ã§ãã åŒæ°ã¯æåã§èšè¿°ã§ããŸããã HelloView.deps = [HelloService]
ã©ã€ããµã€ã¯ã«
ããããã³ã³ããŒãã³ãã®ã©ã€ããµã€ã¯ã«ã¯ã©ãã§ããããã ãããŠããã®äžã«äœã¬ãã«ã®ã³ãŒããæ±ãããšãæ¬åœã«å¿ èŠãªã®ã§ããããïŒ HOCãéããŠãäŸãã°relay / graphqlã®ããã«ããããã®ã©ã€ããµã€ã¯ã«ã¡ãœãããã¡ã€ã³ã³ãŒãããåé€ããããšããŠããŸãã
ããŒã¿ã®æŽæ°ã¯ã³ã³ããŒãã³ãã®è²¬ä»»ã§ã¯ãªããšããèãæ¹ã§ãã ãã®ããŒã¿ã«ã¢ã¯ã»ã¹ããåŸã«ããŒã¿ãããŠã³ããŒãããå ŽåïŒããšãã°ã mobx-utilsã®lazyObservableã䜿çšããå ŽåïŒããã®å ŽåcomponentDidMountã¯å¿ èŠãããŸããã jqueryãã©ã°ã€ã³ãã€ãŸããèŠçŽ ã®refsããããã£ãªã©ããã蟌ãå¿ èŠãããå Žå
ãã³ããŒããã¯ã€ã³è©Šè¬ã®ãªãæ±çšã³ã³ããŒãã³ããçŸåšååšããŠãããšããŸãã å¥ã®ã©ã€ãã©ãªã«å²ãåœãŠããšããŸãããã ã³ã³ããã¹ãã«å ¥ã£ãŠãããã®ãæ¡åŒµããã³ã«ã¹ã¿ãã€ãºããæ¹æ³ã決å®ããããšã¯æ®ã£ãŠããŸãã çµå±ã®ãšãããHelloServiceã¯ç¹å®ã®ããã©ã«ãã®å®è£ ã§ãã
ããã«è¡ã-ã©ãã«ãããããããªããæã£ãŠãã-äœãããããªã
èŠä»¶ã®é »ç¹ãªå€æŽã®ããã«ãã³ã³ããŒãã³ããã«ãã»ã«åã®å¹²æžãéå§ããã¢ããªã±ãŒã·ã§ã³ã®äžéšã§ããå Žåã¯ã©ããªããŸããã ãã¡ããããèªäœã§ã¯ãããŸããããä»æ¥ã®ã»ãŒãã¹ãŠã®ãã¬ãŒã ã¯ãŒã¯ã§å®è£ ãããŠãã圢åŒïŒãã³ãã¬ãŒããé¢æ°ã®æ§æããŸãã¯JSXã®åœ¢åŒïŒã§ãã
ã³ã³ããŒãã³ãã®å Žåããã®ã³ã³ããŒãã³ãçšã«äœãã«ã¹ã¿ãã€ãºããããäºåã«èšãããšã¯ã§ããŸããã ãããŠãèªã¿ããããæãªãããšãªããæåã®å®è£ ãè€éã«ããæåããåå©çšã«æè³ããªãã§ããªãã¡ã¯ã¿ãªã³ã°ããã«ã³ã³ããŒãã³ãã®å éšéšåãå€æŽããæ¹æ³ãå¿ èŠã§ãïŒãªãŒãã³æ§/ã¯ããŒãºæ§ã®åçïŒïŒãã¹ãŠãäºæž¬ããããšã¯ã§ããŸããïŒã
ããšãã°ãDIãªãã§ãç¶æ¿ã«ããã«ã¹ã¿ãã€ãºãæ瀺ããããã«èšèšã§ããŸãã ããªãã¡ æ確ããšéå±€ã倱ããªãããã³ã³ãã³ããå°ããªã¡ãœããã«åå²ããŸãã ãã®ã¢ãããŒãã®æ¬ ç¹ã¯ãèè ãèšäºIdeal UI Frameworkã§æžããŠããŸã ã
class MyPanel extends React.Component { header() { return <div class="my-panel-header">{this.props.head}</div> } bodier() { return <div class="my-panel-bodier">{this.props.body}</div> } childs() { return [ this.header() , this.bodier() ] } render() { return <div class="my-panel">{this.childs()}</div> }
class MyPanelExt extends MyPanel { footer() { return <div class="my-panel-footer">{this.props.foot}</div> } childs() { return [ this.header() , this.bodier() , this.footer() ] } }
ãã®èè ïŒ @vintage ïŒã¯ãéå±€ãç¶æããªããäžèšã®äŸã説æã§ããããªãŒåœ¢åŒãæãã€ãããšèšããªããã°ãªããŸããã å€ãã®äººããã®åœ¢åŒãæ¹å€ããŠãããšããäºå®ã«ãããããããç¹å¥ãªåå²ããªãã¡ã¯ã¿ãªã³ã°ãè¡ããªããŠãã现éšãŸã§åå®çŸ©ã§ãããšããå©ç¹ããããŸãã èšãæããã°ãããã¯ç¡æã®ïŒã»ãšãã©ãæ°ããçããæŠå¿µãç解ããããšã«å ããŠïŒSOLIDã®æåOã§ãã
ãã®ååãJSXã«å®å šã«ç§»è¡ããããšã¯ã§ããŸããããDIãä»ããŠéšåçã«å®è£ ããããšãã§ããŸãã ãã€ã³ãã¯ãéå±€å ã®ã³ã³ããŒãã³ãã¯ãvueã®èŠ³ç¹ããã¯æ¡åŒµãã€ã³ããã¹ãããã§ããããšããããšã§ãã ãããŠã芪ã³ã³ããŒãã³ãã§ã¯ããã®èå¥åïŒå ã®å®è£ ãŸãã¯ã€ã³ã¿ãŒãã§ã€ã¹ïŒãç¥ã£ãŠå®è£ ãå€æŽã§ããŸãã ããã¯äŸåé¢ä¿ã³ã³ããã®æ°ã§ãããå®è£ ãã€ã³ã¿ãŒãã§ã€ã¹ã«é¢é£ä»ããããšãã§ããŸãã
js / tsã§ã¯ãå®è¡æã«ãè€éãããã³ãŒãã®ã»ãã¥ãªãã£ãæãªãæååããŒã®å°å ¥ãªãã§ã¯ãã€ã³ã¿ãŒãã§ã€ã¹ãåç §ã§ããŸããã ãããã£ãŠã次ã®äŸã¯ãããŒãŸãã¯ã¿ã€ãã¹ã¯ãªããã§ã¯æ©èœããŸããïŒãã ããåæ§ã®äŸã¯CïŒãŸãã¯Dartã§æ©èœããŸãïŒã
interface ISome {} class MySome implements ISome {} const map = new Map() map.set(ISome, MySome)
ãã ããæœè±¡ã¯ã©ã¹ãŸãã¯é¢æ°ãåç §ã§ããŸãã
class AbstractSome {} class MySome extends AbstractSome {} const map = new Map() map.set(AbstractSome, MySome)
ãªããªã ãªããžã§ã¯ããšã³ã³ããŒãã³ãã®äœæã¯DIã³ã³ããå ã§è¡ãããå éšã«åæ§ã®ããããååšããå ŽåããããŸãããã®åŸãå®è£ ãåå®çŸ©ã§ããŸãã ãããŠä»¥æ¥ æãåå§çãªãã®ãé€ãã³ã³ããŒãã³ã-é¢æ°ããããã¯åãã€ã³ã¿ãŒãã§ãŒã¹ãæã€ããç°ãªãå®è£ ãæã€é¢æ°ã«çœ®ãæããããšãã§ããŸãã
ããšãã°ãTodoResetButtonViewã¯TodoViewã®äžéšã§ãã ã«ã¹ã¿ã å®è£ ã§TodoResetButtonViewãåå®çŸ©ããå¿ èŠããããŸãã
function TodoResetButtonView({onClick}) { return <button onClick={onClick}>reset</button> } function TodoView({todo, desc, reset}) { return <li> <input type="checkbox" checked={todo.finished} onClick={() => todo.finished = !todo.finished} />{todo.title} #{todo.id} ({desc.title}) <TodoResetButtonView>reset</TodoResetButtonView> </li> }
TodoViewãç·šéããæ©èœããªããšä»®å®ããŸãïŒå¥ã®ã©ã€ãã©ãªã«ããã觊ããããªãããªãŒãã³/ã¯ããŒãºã®ååã«éåããå€ããã¿ã³ã§ããã䜿çšãã11ã®ãããžã§ã¯ããåãã¹ãããŸãïŒã
ãããã£ãŠãæ°ãããã¿ã³ãäœæããæ¢åã®TodoViewãè€è£œããŠãè€è£œå ã§çœ®ãæããŸãã ãã®ç¶æ¿ã§ã¯ãå¯èŠæ§ã®ã¿ã䟵害ãããŸãã-éå±€ãç¶æãããããããã¿ã³ã亀æã§ããããã«TodoViewãç¹å¥ã«èšèšããå¿ èŠã¯ãããŸããã
function ClonedTodoResetButtonView({onClick}) { return <button onClick={onClick}>cloned reset</button> } const ClonedTodoView = cloneComponent(TodoView, [ [TodoResetButtonView, ClonedTodoResetButtonView] ], 'ClonedTodoView') const ClonedTodoListView = cloneComponent(TodoListView, [ [TodoView, ClonedTodoView] ], 'ClonedTodoListView') ReactDOM.render(<ClonedTodoListView todoList={store} />, document.getElementById('mount'));
ã³ã³ããŒãã³ãã ãã§ãªããäŸåé¢ä¿ãåå®çŸ©ããå¿ èŠãããå ŽåããããŸãã
class AbstractHelloService { name: string } function HelloView(props: {greet: string}, service: AbstractHelloService) { return <div> {props.greet}, {service.name} <br/><input value={service.name} onChange={(e) => { service.name = e.target.value }} /> </div> } class AppHelloService { @mem name = 'Jonny' } function AppView() { return <HelloView greet="Hello"/> } AppView.aliases = [ [AbstractHelloService, AppHelloService] ]
HelloViewã¯AppHelloServiceã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ãåãåããŸãã ãªããªã ãã¹ãŠã®åã³ã³ããŒãã³ãã®AppView.aliases
ãAbstractHelloServiceããªãŒããŒã©ã€ãããŸãã
ãã¡ãããç¶æ¿ã«ããããã¹ãŠãã«ã¹ã¿ãã€ãºãããã¢ãããŒãã«ã¯ãã€ãã¹ããããŸãã ãªããªã ãã¬ãŒã ã¯ãŒã¯ã¯ããå€ãã®æ¡åŒµãã€ã³ããæäŸãããããã«ã¹ã¿ãã€ãºã®è²¬ä»»ã¯ã³ã³ããŒãã³ããèšèšããã®ã§ã¯ãªããã³ã³ããŒãã³ãã䜿çšãããã®ã«ç§»ããŸãã æå³ãèªèããã«ãããŒãã«ãã³ã³ããŒãã³ãã®äžéšãåå®çŸ©ãããšã誀ã£ãŠããªã¹ããã«å€ããããšãã§ããŸãããããã¯æªãå åã§ãã ã¯å ã®æå³ã®æªã¿ã§ã ïŒ LSPã®ååã«éåããŠããŸãïŒã
ç¶æ åé¢
ããã©ã«ãã§ã¯ãã³ã³ããŒãã³ãã®äŸåé¢ä¿ã®ç¶æ ãåã³ã³ããŒãã³ãã«å²ãåœãŠãããŸãã ãã ããäžè¬çãªååãé©çšãããŸããäžèšã®ã³ã³ããŒãã³ãã§å®çŸ©ãããŠãããã®ã¯ãã¹ãŠãåºç€ãšãªãäŸåé¢ä¿ãããåªå ãããŸãã ããªãã¡ äŸåé¢ä¿ãæåã«èŠªã³ã³ããŒãã³ãã§äœ¿çšãããå ŽåãäŸåé¢ä¿ã¯ãã®äŸåé¢ä¿ãšå ±ã«åç¶ããäŸåé¢ä¿ãèŠæ±ãããã¹ãŠã®åºç€ãšãªãã³ã³ããŒãã³ãã¯ã芪ã€ã³ã¹ã¿ã³ã¹ãæ£ç¢ºã«åãåããŸãã
class HelloService { @mem name = 'John' } function HelloView(props: {greet: string}, service: HelloService) { return <div> {props.greet}, {service.name} <br/><input value={service.name} onChange={(e) => { service.name = e.target.value }} /> </div> } class AppHelloService { @mem name = 'Jonny' } function AppView(_, service: HelloService) { return <div> <HelloView greet="Hello"/> <HelloView greet="Hi"/> </div> }
ãã®æ§æã§ã¯ãäž¡æ¹ã®HelloViewãHelloServiceã®å ±éã€ã³ã¹ã¿ã³ã¹ãå ±æããŸãã ãã ããAppViewã«HelloServiceããªãå Žåãååã³ã³ããŒãã³ãã«ã¯ç¬èªã®ã€ã³ã¹ã¿ã³ã¹ããããŸãã
function AppView() { return <div> <HelloView greet="Hello"/> <HelloView greet="Hi"/> </div> }
ãªããžã§ã¯ããã©ã®ã³ã³ããŒãã³ãã«å±ããããå¶åŸ¡ã§ããå Žåãåæ§ã®ååãæ ŒçŽåº«ã®éå±€DIã§äœ¿çšãããŸã ã
ã¹ã¿ã€ã«
ç§ã¯ãcss-in-jsã¢ãããŒããWebã§äœ¿çšããå¯äžã®æš©å©ã§ãããšèšã£ãŠããã®ã§ã¯ãããŸããã ããããããã§ã¯äŸåæ§æ³šå ¥ã®èãæ¹ãé©çšã§ããŸãã ãã®åé¡ã¯ãredux / mobxããã³ã³ã³ããã¹ãã«é¢ããäžèšã®åé¡ã«äŒŒãŠããŸãã ããšãã°ãå€ãã®åæ§ã®ã©ã€ãã©ãªãšåæ§ã«ãjsã¹ã¿ã€ã«ã¯injectSheetã©ãããŒãä»ããŠã³ã³ããŒãã³ãã«åºå®ãããã³ã³ããŒãã³ãã¯react-jssã䜿çšããŠç¹å®ã®ã¹ã¿ã€ã«å®è£ ã«é¢é£ä»ããããŸãã
import React from 'react' import injectSheet from 'react-jss' const styles = { button: { background: props => props.color }, label: { fontWeight: 'bold' } } const Button = ({classes, children}) => ( <button className={classes.button}> <span className={classes.label}> {children} </span> </button> ) export default injectSheet(styles)(Button)
ãã ããjssãªã©ãžã®ãã®çŽæ¥ã®äŸåã¯ããã®è²¬ä»»ãDIã«è»¢éããããšã§åé€ã§ããŸãã ã¢ããªã±ãŒã·ã§ã³ã³ãŒãã§ã¯ãã¹ã¿ã€ã«ãæã€é¢æ°ãã³ã³ããŒãã³ãã®äŸåé¢ä¿ãšããŠå®çŸ©ããããã«å¿ããŠããŒã¯ããã ãã§ååã§ãã
// ... setup import {action, props, mem} from 'lom_atom' import type {NamesOf} from 'lom_atom' class Store { @mem red = 140 } function HelloTheme(store: Store) { return { wrapper: { background: `rgb(${store.red}, 0, 0)` } } } HelloTheme.theme = true function HelloView( _, {store, theme}: { store: Store, theme: NameOf<typeof HelloTheme> } ) { return <div className={theme.wrapper}> color via css {store.red}: <input type="range" min="0" max="255" value={store.red} onInput={({target}) => { store.red = Number(target.value) }} /> </div> }
ãã®ãããªã¹ã¿ã€ã«ã®ã¢ãããŒãã«ã¯ãDIã®ãã¹ãŠã®å©ç¹ããããããŒããšåå¿æ§ãæäŸããŸãã cssã®å€æ°ãšã¯ç°ãªããflow / tsã®åã¯ããã§æ©èœããŸãã ãã€ãã¹-CSSã®çæãšæŽæ°ã®ãªãŒããŒãããã
ãŸãšã
ã³ã³ããŒãã³ãã®äŸåæ§æ³šå ¥ã®èãæ¹ãé©å¿ãããããã«ã reactive-diã©ã€ãã©ãªãŒãå ¥æããŸããã èšäºã®ç°¡åãªäŸã¯ããã«åºã¥ããŠããŸãããèªã¿èŸŒã¿ãããŠã³ããŒãã¹ããŒã¿ã¹ã®åŠçããšã©ãŒãªã©ã ããè€éãªäŸããããŸãã åå¿ãäºååå¿ãã€ã³ãã§ã«ãã®todomvc ãã³ãããŒã¯ããããŸã ã ããã§ãreactive-diã䜿çšããŠãªãŒããŒããããè©äŸ¡ã§ããŸãã 確ãã«ã100ã®ä»äºã§ããã®ãªãŒããŒãããããã倧ããªæž¬å®èª€å·®ããããŸããã
çµæã¯ãç°¡ç¥åãããAngularã§ãã ãã ããreactive-diã«ã¯å€ãã®æ©èœããããŸã
- ã¯ãªãŒã³ãªãªã¢ã¯ã·ã§ã³ã§ã¬ã¬ã·ãŒã³ã³ããŒãã³ããšã®äºææ§ãç¶æããªãããreactããã³ãã®ã¯ããŒã³ãšçµ±åå¯èœ
- mobx / observeãªã©ã§çŽç²ãªã³ã³ããŒãã³ããã©ããããã«èšè¿°ããããšãã§ããŸã
- ã¯ã©ã¹ã ãã§ãªããã³ã³ããŒãã³ãé¢æ°ã«å¯ŸããŠãããããŒã¿ã€ãã®ã¿ã€ããšããŸãæ©èœããŸã
- æ§ããïŒã³ãŒãå ã«ãã³ã¬ãŒã¿ã®ããŒãã¯å¿ èŠãããŸãããã³ã³ããŒãã³ãã¯åå¿ããæœè±¡åãããã¡ã€ã³ã³ãŒãã«åœ±é¿ãäžããããšãªãå®è£ ã«å€æŽã§ããŸãã
- æ§æãç°¡åã§ãäŸåé¢ä¿ã®ç»é²ãäžèŠã§ãæäŸ/æ³šå ¥ã®ãããªæ§é ãæäŸããŸã
- å éšã®éå±€ãç¶æããªãããã³ã³ããŒãã³ãã®å 容ãå€æŽããã«åå®çŸ©ã§ããŸãã
- ã€ã³ã¿ãŒãã§ã€ã¹ãä»ããŠcss-in-jsãœãªã¥ãŒã·ã§ã³ãã³ã³ããŒãã³ãã«æ§ããã«çµ±åã§ããŸã
ãªãã³ã³ããã¹ããšããèãæ¹ããŸã ãã®ããã«çºå±ããŠããªãã®ã§ããïŒ ãããããããã³ããšã³ãã§ã®DIã®äžäººæ°ã¯ããããŒ/ tsã®ããã»ã©åºããªãåªäœæ§ãšãã¡ã¿ããŒã¿ã¬ãã«ã§ã®æšæºã€ã³ã¿ãŒãã§ã€ã¹ãµããŒãã®æ¬ åŠã«ãããã®ã§ãã æ·±ãåèããããšãªããä»ã®ããã¯ãšã³ãæåèšèªïŒCïŒã®InversifyJSã¯ããŒã³Ninjectãªã©ïŒããè€éãªå®è£ ãã³ããŒããããšããŸãã ãããŸã§ã®åŒ·èª¿ãäžååã§ããã ãã§ãªããäŸãã°ãDIã®é¡äŒŒæ§ã¯åå¿ãšãã¥ãŒã«ãããŸããããããã®å®è£ ã¯ãã¬ãŒã ã¯ãŒã¯ã®äžå¯æ¬ ãªéšåã§ããããã®åœ¹å²ã¯äºæ¬¡çã§ãã
è¯ãDIã¯è§£æ±ºçã®ååã§ãã äžèšã®äŸã§ã¯ã @mem
ãã³ã¬ãŒã¿ãé »ç¹ã«ç¹æ»
ããŸãããããã¯ã PPRã®ã¢ã€ãã¢ã«åºã¥ããŠæ§ç¯ãããç¶æ
ã管çããããã«å¿
èŠã§ãã memã䜿çšãããšãmobxãšæ¯èŒããŠåçŽãªãšã©ãŒåŠçãšããŒãã¹ããŒã¿ã¹ã䜿çšããŠãæ¬äŒŒåæã¹ã¿ã€ã«ã§ã³ãŒããèšè¿°ã§ããŸãã 次ã®èšäºã§åœŒã«ã€ããŠã話ããŸãã