ãã¥ãŒããªã¢ã«ã®
åã®éšåã§ãå圢ã«ãŒãã£ã³ã°ãããã²ãŒã·ã§ã³ããã§ãããããã³ããŒã¿ã®åæç¶æ
ã®åé¡ã解決ããŸããã ãã®çµæãååã¢ããªã±ãŒã·ã§ã³ã®ããªãåçŽã§ç°¡æœãªåºç€ã§ããããšã倿ããŸãããããã¯ãå¥ã®ãªããžããª
ractive-isomorphic-starterkitã«ãå²ãåœãŠãŸããã ãã®ããŒãã§ã¯ã
RealWorldã¢ããªã±ãŒã·ã§ã³ã®äœæãéå§ããŸãããæåã«ãããåè§£ããŸãã è¡ããïŒ

åŸæ¥ã®ãªããããã¯
è峿·±ãçµæã¯ã
ç¶æ
ããŒã¹ã®ã«ãŒãã£ã³ã°ã«é¢ãã
ã¢ã³ã±ãŒãã§ç€ºãããŸããã ãã®ã¢ã€ãã¢ã«æç¥šãã人ã®åæ°ã¯ãæåŸ
ããããã®ã«æè¬ããŸããã§ããã ããã§ããã¢ã€ãã¢ã®ååã¯ããŸã ã«èå³ããããŸããã
è峿·±ãäºå®ã¯ãæè¿ãããã³ããšã³ãã§YaãSubbotnikã蚪ããããšã§ãã Yandexã®ã¡ã³ããŒã¯ã
ç¶æ
ããŒã¹ã®ã«ãŒãã£ã³ã°ã®ã¢ã€ãã¢ã
å³ãã£ãããã§ãã ãã®ãããã¯ã«è§Šããã¹ããŒã«ãŒã¯ãã¢ãã£ãªãšã€ãã€ã³ã¿ãŒãã§ãŒã¹ã®ããŒã ããã®ãã®ã§ãããæããã«æ¬¡ã®ããã«èŠããŸãã
<Match strict state={{page}} params={{status: 'NEW', query: 'Yandex'}} > <App>...</App> </Match> <Switch> ... </Switch>
å®éãããã¯ååãšããŠç§ãããããšãšåãã§ãïŒ
{{#if $route.match(page) && status === 'NEW' && query === 'Yandex'}} <App>...</App> {{/if}}
è±ã®ã³ã³ããŒãã³ããäœæãã以å€ã«ãä»ã®è¡šçŸææ®µãæããªã
Reactã䜿çšãããšããäºå®ããªãéããããããã®ã¹ã¿ã€ã«ã§ãã
ã¬ããŒãã®çµããã«
ãç§ã¯ç¹ã«ãã®éšåã«åã³çŠç¹ãåãããŸããã ãããããã¹ããŒã«ãŒã¯åœŒã®ãããžã§ã¯ãã®è©³çŽ°ã«æ·±ã没é ããå€ãã®äººã圌ã®ã¢ã€ãã¢ãå®å
šã«çè§£ã§ããªãã£ãããã«æããŸããã
åè§£ãšåæ

éåžžã«ç°¡åã«èšãã°ãããã³ããšã³ãã®ã³ã³ããã¹ãã§ã¯ãåè§£ã¯ã¢ããªã·ãã¯ã¢ããªã±ãŒã·ã§ã³ãã³ã³ããŒãã³ãã«åå²ããããã»ã¹ã§ããããããããåé¡ã®äžéšã解決ããŸãã åè§£ã®äž»ãªç®çã¯ãçµéšçãªè€éãã軜æžãã
DRYååãå®è£
ããããšã§ãã
ããã¯ãææ°ã®ããã³ããšã³ããæ¯é
ããã³ã³ããŒãã³ãã¢ãããŒãã§ãããå
šäœãšããŠã¢ãžã¥ã©ãŒã¢ãããŒãã®äžéšã§ãã ã€ãŸããã³ãŒããã¢ãžã¥ãŒã«ã«åå²ããã€ã³ã¿ãŒãã§ã€ã¹ãã³ã³ããŒãã³ãã«åå²ããŸãã ç¹°ãè¿ããŸãããããã³ããšã³ãã®ã³ã³ããã¹ãã§ã¯ãã³ã³ããŒãã³ãã¯UIãããžãã¹ããžãã¯ãªã©ã®äžéšãã«ãã»ã«åããç¹å®ã®ãŠãŒã¶ãŒèŠçŽ ã§ãã ã³ã³ããŒãã³ããçè§£ããäžã§éèŠãªã³ã³ããŒãã³ãã¯ãåè§£ãçºçããåçã§ãã
åè§£ã«ã¯å€ãã®ã¢ãããŒãããããŸãã ããšãã°ã
Reactã¯ããã¹ãŠãã³ã³ããŒãã³ãã§ããããšããååã䜿çšããŠãããä»ã®ãã¬ãŒã ã¯ãŒã¯ã¯
SOLIDãªã©ã®ã³ã³ããã¹ãã§ã³ã³ããŒãã³ããèæ
®ããŠããŸãã ããããäžè¬ã«ãããã¯ãã¹ãŠãã
é«åé ã
ççµå ããšåŒã°ããã³ã³ããŒãã³ããäœæããããšãã顿ã«
åž°çããŸãã
圌ãã¯çãããçè§£ããŠããããã«èŠãããšããäºå®ã«ããããããããã®çè§£ã¯éåžžã«é »ç¹ã«ç°ãªãæ¹æ³ã§å®è£
ãããŠããŸãã 2人ã®éçºè
ãé£ããŠè¡ãå Žåãé«ã確çã§ã圌ãã¯ããŸããŸãªæ¹æ³ã§ã¢ããªã±ãŒã·ã§ã³ãåè§£ããŸãã ç§èªèº«ãåºå®ããåè§£ã®ååã®ã¿ã説æããŸãã
ççŽã«èšã£ãŠãã³ã³ããŒãã³ãããç²ç ãããã®ã¯æ£ãããšã¯æããã
Reactã³ã³ããŒãã³ããç²ç ããåçã¯ç§ã«ã¯ããŸã
䌌ãŠããŸããã ååãšããŠã次ã®ã«ãŒã«ã«åŸã£ãŠã³ã³ããŒãã³ããéžæããŸãã
- åå©çš -ã¢ããªã±ãŒã·ã§ã³ã®ç°ãªãéšåã§åãæ©èœã䜿çšããŸãã
- æ©èœçãªç®ç -æç¢ºã«å®çŸ©ãããæ©èœãšãå¥åã®ã©ã€ããµã€ã¯ã«ãšæ¡ä»¶ãæã€ããžãã¹ããã»ã¹
- æ§é çæ©èœ -æ§é ãæ¹åããã³ãŒãã®å¯èªæ§ãé«ãã
ã¢ããªã±ãŒã·ã§ã³ã®äžéšãå¥ã®ã³ã³ããŒãã³ãã«å²ãåœãŠãä»ã®çç±ã¯ãªããšæãããŸãã ããã«ãéã«é床ã®åè§£ã¯ããããžã§ã¯ããšãã®ãµããŒãã®çè§£ãè€éã«ããå¯èœæ§ããããŸãã èšãæããã°ããã®åé¡ã§ã¯ãã©ã³ã¹ãéåžžã«éèŠã§ãã
Reactã«ã€ããŠã®å®å
šãªçå®ïŒæ°åŒ±ãªäººåãã§ã¯ãªãïŒç§ã¯ã«ã«ãã®ãšã³ããªãŒã§å«ããã€ããããšæããŸãããããã§ãç§ã¯
çŽç²ã«äž»èгçãªæèŠã衚æããŸã ïŒïŒïŒ
Reactã®ããã€ãã®åŽé¢ã«ã€ããŠã ãããã
Reactã説åŸããã¢ãããŒããšãã®ä¿¡è
ã説æããŸãã
ç§ã¯
JSXã«ã€ããŠããããŠãããã©ãã»ã©ã²ã©ãã®ãã«ã€ããŠã¯æ³£ããŸãããããã«ã€ããŠã¯ãã§ã«äœååãèšãããŠããŸãã ãããŠãã³ãŒããšããŒã¯ã¢ãããæ··åãããšããèãã¯ãreactã«å±ããŠããã®ã§ã¯ãªããããã
PHPã«å±ããŠããã®ã§ãããããã¯reactã«ç§»è¡ããŸããã éšåçã«ã
ããã§ã¯ã
Reactãåè§£ããåçãšã
Reduxããã®ä»ã®
Fluxã®ãããªãã®ã«å¯ŸããçŽæ¥çãªåœ±é¿ã«ã€ããŠèª¬æããŸãã é©ããããããŸããããããããåå¿ãããããããé©åœçãªãã¢ã€ãã¢ã®ãã¹ãŠã®çç±ã§ãããšæèšããŸãã åæã«ãããã°ã©ãã³ã°ã®ååãäœå幎ã«ãããã£ãŠéçºããŠãã
ãã¹ããã©ã¯ãã£ã¹ããã¹ãŠããã®éãåãéããŸãã
ãããŠãå¡©ã¯äœã§ããïŒ ãªããšããå¡©ã1 ....
åå¿ Â»
ããããããšã§ããã
ãã¹ãŠã¯çŽ æŽãããã¢ã€ãã¢ããå§ãŸã£ããšæããŸãã
ããã¹ãŠãã³ã³ããŒãã³ãã§ãã ã ãã®ã¢ã€ãã¢ã¯éåžžã«ã·ã³ãã«ã§çè§£ããããããã人ã
ã®å¿ãæããããšãã§ããŸãã ãã®åçŽãã«å¯Ÿããé床ã®ç±æã¯ãå®éã
Reactãä»ã«äœãã§ããªããšããäºå®ã«ã€ãªãããŸããã ã³ã³ããŒãã³ããšãã®æ§æãäœæãã以å€ã®è¡šçŸææ®µã¯ãããŸããïŒããã§ã¯ã
ä»®æ³DOMããã®ä»ã®ãšã³ãžã³ããŒãã¯ãã¢ãŒããã¯ãã£ã®èгç¹ããã¯ããã»ã©éèŠã§ã¯ãªããããããã§ã¯ç¹ã«èæ
®ããŸããïŒã
ä»ã®æåã®ã·ã³ãã«ã§çæ³çãªã¢ã€ãã¢ãšåæ§ã«ãåå¿ã®ã¢ã€ãã¢ã«ãçŸå®ããããŸããã ãããã
Reactã®äœæè
ã¯ãã®ã¢ã€ãã¢ã«éåžžã«ç±å¿ã§ããã¬ãŒã ã¯ãŒã¯å
ã§ã¯ãªãïŒä»ã®äººãããã§ããããã«ïŒé床ã®è€éãã«èãå§ããŸããããã¢ããªã±ãŒã·ã§ã³å
ã«æ®ããé è³ã®èŠããã®ã·ã³ãã«ããä¿ã¡ãŸãã ãŸãã
Reactã¯åžžã«åãããã«çããŸããã¢ããªã±ãŒã·ã§ã³å
ã®ãã¹ãŠãã³ã³ããŒãã³ãã§ãããããã³ã³ããŒãã³ããäœæããã ãã§ãã
ã³ãã¥ããã£ããããã®ååã«é å¿ããããã«ã¯ããããæããŠããããšã¯æããã§ãã ããã§ããããã¯ãã®ã¢ããªã±ãŒã·ã§ã³ãé床ã«è€éã«ãå§ããŸãããããã¬ãŒã ã¯ãŒã¯ã§ã¯ãªãè¡æã©ã€ãã©ãªãŒã§ããã ãã®ãããååãšããŠã
Reactã®ã¿ã§ã¢ããªã±ãŒã·ã§ã³ãäœæããããšã¯ãããŸããã 圌ã®èåŸã«ã¯ãããããçš®é¡ã®ã¢ããªã³ãšæŸèæã®åè»ã確å®ã«äŒžã³ãŠããŸãã
ãããšã¯å¥ã«ã
Angularã®ãããª
ããªãŒã«ã€ã³ã¯ã³ããœãªã¥ãŒã·ã§ã³ã®å€§ãã¡ã³ã§ããªãããšã«æ³šæããŠãã ããã ãã¬ãŒã ã¯ãŒã¯ã®ç¹æš©ã¯ãã¢ããªã±ãŒã·ã§ã³ã®ã¢ãŒããã¯ãã£ã®åé¡ãåè§£ãšæ§æã®åé¡ãã³ã³ããŒãã³ãéã®éä¿¡ã«é¢é£ããŠãããã¹ãŠã ãšæããŸãã ããããhttp-requestãªã©ã®éä¿¡ã«é¢ãã質åã¯ãããŸããã ç§ã«ãšã£ãŠã
Angularã¯å€ããã
Reactã¯å°ãªãããŸãã
ããããåè§£ãšãå¥ã®ã³ã³ããŒãã³ããäœæããããšããååã«æ»ããŸãã ãã®çµæãããããã¹ãŠã®çŽ æŽããããæ¬è³ªçã«ãã¢ã€ãã¢ã¯2ã€ã®äž»ãªãã®ã«ã€ãªãããŸããã
- ã³ã³ããŒãã³ããäœæããããšã§åé¡ã解決ããããããã³ã³ããŒãã³ãããããããããŸããããããã¯å°ããã®ã§ãããŒã¯ã¢ãããšã³ãŒããæ··ããŠãäžåã«èŠããŸããã
- ã¢ããªã±ãŒã·ã§ã³ã®ã³ã³ããŒãã³ããžã®åŒ·åãªæçåã«ãããã³ã³ããŒãã³ãã®æ§æãäžå¿
èŠã«è€éã«ãªããç°ãªãã¬ãã«ã®ã³ã³ããŒãã³ãéã§éä¿¡ããããšãé£ãããªããŸãã ç¹ã«ãäžæ¹åã®ããŒã¿ãããŒãã®ååãšçµã¿åãããŠã ããã¯ãæãæãããªè§£æ±ºçãã°ããŒãã«ãªç¶æ
ãä»ããã³ãã¥ãã±ãŒã·ã§ã³ã§ãããšããäºå®ã«ã€ãªãããŸãã
ãããã£ãŠã
ããã¹ãŠãã³ã³ããŒãã³ãã§ãã
ããšããååã®mané ãªéµå®ãšã
Reactãæåã«å¶åŸ¡ãããªãåè§£ãåŒãèµ·ãããæ¬¡ã«ã³ã³ããŒãã³ãã®æ§æãè€éã«ãããã®åŸèããæé·ããªãã£ãã®ã¯ãä»ã®ããŒã«ã®æ¬ åŠã§ãã ã³ãŒãåââé¢ãšããŒã¯ã¢ããã®äžè¬ã«åãå
¥ããããŠããååãç¡èŠãããã¹ãŠãããŒãå
ã«ãããšãããããã¯ãŒã«ã§ãããšä¿¡è
ã«ç¢ºä¿¡ãããããšãã§ããŸãã ã°ããŒãã«ç¶æ
ã®äœ¿çšã«é²ãããšãã§ããŸãããé·å¹Žã«ããã£ãŠãããã®ç¶æ
ãåé¢ããŠã«ãã»ã«åããããšããŸããã èŠããã«ãåºç€ãæºãããªããã®ã«ä¿ã€ããã«ãããããçš®é¡ã®çæ°ãããŠãã ããã
ããªããç§ã®æèŠã«åæããªãå ŽåããŸãã¯äœãã§ç§ãä¿®æ£ãããå Žå-ã³ã¡ã³ãã
æè¿ããŸãã äžè¬ã«ã掻æ°ã®ããè°è«ã¯ãã«ã«ãã®ç¡èšã®vyéšãããã¯ããã«çç£çãªãã®ã ãšæããŸãã åãã£ãŠæè¬ããŸãã ç§èªèº«ãã誰ããæããããæããããããããããŸããã§ããã
ãŸããã¡ã€ã³ããŒãžãšãŠãŒã¶ãŒãããã¡ã€ã«ããŒãžãåè§£ããŠã¿ãŸãããã ãŸãããããå®çŸãããã§ãã
ã¡ã€ã³ããŒãž

ããã§ã察å¿ããã³ã³ããŒãã³ããè²ä»ãã®ãã¬ãŒã ã§åŒ·èª¿è¡šç€ºããŸããã
- 玫è²ã®ãã¬ãŒã -ã«ãŒãã³ã³ããŒãã³ãïŒã«ãŒãïŒãŸãã¯ã¢ããªã±ãŒã·ã§ã³ã³ã³ããŒãã³ãã
- éããã¬ãŒã ã¯ã¿ã°ãªã¹ãã®ã³ã³ããŒãã³ãã§ãã
- èµ€æ -èšäºã®ãªã¹ãã®ã³ã³ããŒãã³ãã
- ããŒãžã¥ãã¬ãŒã -ãæ°ã«å
¥ãã«è¿œå ããã³ã³ããŒãã³ãã
ãŸããã¡ã€ã³ããŒãžã«ã¯ãã¹ã¯ãªãŒã³ã·ã§ããã«åãŸããªãèšäºã®ãªã¹ãçšã®ããŒãžããŒã·ã§ã³ã³ã³ããŒãã³ããåã蟌ãŸããŠããŸãã
ã¿ã°ã³ã³ããŒãã³ãã¯æããã«åå©çšå¯èœã§ããããšã«æ³šæããŠãã ããã åæ§ã«ããæ°ã«å
¥ãã«è¿œå ããã³ã³ããŒãã³ãã
ãŠãŒã¶ãŒãããã¡ã€ã«

èšäºãã¿ã°ããæ°ã«å
¥ãã®ãªã¹ãã®ã³ã³ããŒãã³ãããããŸãã æ°ããããããïŒ
- ç·è²ã®ãã¬ãŒã -ãŠãŒã¶ãŒãããã¡ã€ã«ã®ã³ã³ããŒãã³ãã
- é»è²ã®ãã¬ãŒã ã¯ããŠãŒã¶ãŒãµãã¹ã¯ãªãã·ã§ã³ã³ã³ããŒãã³ãã§ãã
ããŒãžããŒã·ã§ã³ã³ã³ããŒãã³ããã¹ã¯ãªãŒã³ã·ã§ããã«åãŸããŸããã§ãããããŠãŒã¶ãŒã®èšäºã®ãªã¹ããé·ããªãå¯èœæ§ããããããããã§æ€èšãã䟡å€ããããŸãã èšäºãªã¹ãã³ã³ããŒãã³ããåå©çšå¯èœã§ããããšãæããã«ãªããŸãã
ãã®ãããªã³ã³ããŒãã³ããžã®åé¢ã¯ãã©ã³ã¹ãåããŠãããåè§£ã®ç®æšãéæããã®ã«æäœéå¿
èŠã§ãããšæããŸãã åæã«ãã³ã³ããŒãã³ãã®æ§æã¯éåžžã«ã·ã³ãã«ã§ç®¡çãããããŸãŸã§ãã
ã³ã³ããŒãã³ãã®çš®é¡

ç§ã«ã¯ã3ã€ã®äž»èŠãªã¿ã€ãã®ã³ã³ããŒãã³ããããããã«æããŸãïŒ
- çŽç²ãªã³ã³ããŒãã³ãã¯åçŽãªã³ã³ããŒãã³ãã§ããããã®çµæã¯å
¥åãã©ã¡ãŒã¿ãŒã«å®å
šã«äŸåããŸãïŒãçŽç²ãªã颿°ã®ã¿ã€ãã«ããïŒã å®å
šã«åå©çšãããä»ã®ã³ã³ããŒãã³ããšã®åæã§ããŸãæ©èœããŸãã
- èªåŸã³ã³ããŒãã³ãã¯ãããçš®ã®åé¢ãããæ©èœãå®è£
ãã SOLIDã®ååãå®è£
ããè€éãªã³ã³ããŒãã³ãã§ãã ååãšããŠããã®ãããªã³ã³ããŒãã³ãã¯ããçŽç²ãªãã³ã³ããŒãã³ããšã®çµã¿åããã§äœ¿çšãããç¹å®ã®ããžãã¹ããžãã¯ãå®è£
ããããŒã¿ãåéããŸãã
- ã©ããã³ã³ããŒãã³ãã¯ããã³ãã¬ãŒãã®æ§é ã®æ¹åããã©ã¡ãŒã¿ã®åãæž¡ããªã©ã«æããã䜿çšãããåé¢ãããã³ã³ããŒãã³ãã§ã¯ãããŸããã
ç§ãäœåºŠãèšã£ãããã«ãçŸå®ã®äžçã§ã¯ãã¹ãŠãããã»ã©æç¢ºã§ã¯ãªããããã³ã³ããŒãã³ãã«ã¯ãã°ãã°ç¹åŸŽãæ··åšããŠãããããã¯æ£åžžã§ãã
ã³ãŒããæžã
ã«ãŒãã³ã³ããŒãã³ã
ã«ãŒãã³ã³ããŒãã³ããŸãã¯ã¢ããªã±ãŒã·ã§ã³ã³ã³ããŒãã³ãã¯ã.
/src/app.jsã§èšå®ããã³äœæãã
Ractiveã€ã³ã¹ã¿ã³ã¹ã§ãã ãŸããäžè¬çãªã¢ããªã±ãŒã·ã§ã³ã¬ã€ã¢ãŠãïŒã¬ã€ã¢ãŠãïŒãå®è£
ããç»é¢äžã«åžžã«ååšããèŠçŽ ïŒããããŒãšããã¿ãŒïŒãšãã«ãŒãã£ã³ã°ãå«ãã¢ããªã±ãŒã·ã§ã³å
šäœã®ã¬ã€ã¢ãŠããå«ã¿ãŸãã
ãã³ãã¬ãŒãã®æ§é ãæ¹åããäžè¬çãªã¬ã€ã¢ãŠããããå°ããªéšåã«åå²ããããã«ãåã®ã»ã¯ã·ã§ã³ã§èª¬æãã
ã©ãããŒã³ã³ããŒãã³ãã䜿çšã§ããŸãã
Ractiveã§ã¯ ãåçŽãªããããã£ãèšå®ããããšã«ãããã³ã³ããŒãã³ããéåé¢ã«ã§ããŸãã
{ isolated: false }
ãã ããã³ã³ããŒãã³ãèªäœã¯ãå®äŸ¡ãã§ã¯ãããŸããããããã®ãã¹ãŠã®ãªã¢ã¯ãã£ãããã³èšç®ãããããããã£ããªãã¶ãŒããŒãã©ã€ããµã€ã¯ã«ãªã©ãå«ãŸããŠããããã§ãã å®éã
Ractiveã³ã³ããŒãã³ãã¯çµã¿èŸŒã¿ç¶æ
ãæã¡ãäœããã®æ©èœãå®è£
ããã¯ã©ã¹ã§ãã ã©ãããŒãããããã¹ãŠã®åœ¢åŒã§å¿
èŠãšããããã³ãã¬ãŒããåçŽåããããã«èšèšãããæ§é èŠçŽ ã«ãããªãå Žåãå¥ã®çµã¿èŸŒã¿åè§£ã¡ã«ããºã ã§ãã
partialã䜿çšããã®ã¯éåžžã«ãå®ãããªããŸãã
åã®èšäºã®
ããŒã·ã£ã«ã§åžœåãšå°äžå®€ããã§ã«åãåºããŸããã åæ§ã«ãããã¹ãŠãã³ã³ããŒãã³ãã§ã¯ãªãããããã³ã³ããŒãã³ãã®ç¹æ§ãæºãããªãã¬ã€ã¢ãŠãã®ä»ã®éšåãå®è£
ããŸãã ;-)
ãããã£ãŠããã®æ®µéã§ã¯ãã«ãŒãã¢ããªã±ãŒã·ã§ã³ãã³ãã¬ãŒãã¯æ¬¡ã®ããã«ãªããŸãã
./src/templates/app.html {{>navbar}} {{#with @shared.$route as $route, {delay: 500} as fadeIn, {duration: 200} as fadeOut }} <div class="page"> {{#if $route.match('/login') }} <div class="auth-page" fade-in="fadeIn" fade-out="fadeOut"> Login page </div> {{elseif $route.match('/register') }} <div class="auth-page" fade-in="fadeIn" fade-out="fadeOut"> Register page </div> {{elseif $route.match('/profile/:username/:section?') }} <div class="profile-page" fade-in="fadeIn" fade-out="fadeOut"> Profile page </div> {{elseif $route.match('/') }} <div class="home-page" fade-in="fadeIn" fade-out="fadeOut"> {{>homepage}} </div> {{else}} <div class="notfound-page" fade-in="fadeIn" fade-out="fadeOut"> {{>notfound}} </div> {{/if}} </div> {{/with}} {{>footer}}
以äžã
RealWorldãããžã§ã¯ãã®
ã«ãŒãã£ã³ã°ã®
ã¬ã€ãã©ã€ã³ã䜿çš
ããŸã ã ã¬ã€ãã«ç¹å®ã®æšå¥šäºé
ãå«ãŸããŠããªãå Žæã§ã¯ãæ£ãããšæãããã¢ãããŒãã䜿çšããŸãã ç§ãã¡ã¯å圢ã®ã¢ããªã±ãŒã·ã§ã³ãæžããŠããã®ã§ãããã·ã¥ã«ãŒãã£ã³ã°ã®ä»£ããã«
History APIã«ãŒãã£ã³ã°ã䜿çšããŸãããåç¥ã®ããã«ãURLãã©ã°ã¡ã³ãã¯ãµãŒããŒã«ç§»åããŸããã
ããã«ãã¡ã€ã³ããŒãžã®ã¬ã€ã¢ãŠãçšãš404ããŒãžçšã®2ââã€ã®
ããŒã·ã£ã«ã匷調ããŸããã
./src/templates/partials/homepage.html <div class="banner"> <div class="container"> <h1 class="logo-font">conduit</h1> <p>A place to share your knowledge.</p> </div> </div> <div class="container page"> <div class="row"> <div class="col-md-9"> <div class="feed-toggle"> <ul class="nav nav-pills outline-active"> <li class="nav-item"> <a href="/" class-active="$route.pathname === '/'" class="nav-link"> Global Feed </a> </li> </ul> </div> Articles list </div> <div class="col-md-3"> <div class="sidebar"> <p>Popular Tags</p> Tags list </div> </div> </div> </div>
./src/templates/partials/notfound.html <div class="banner"> <div class="container"> <h1 class="logo-font">conduit</h1> <p>404 - Not found</p> </div> </div>
次ã«ãã«ãŒãã³ã³ããŒãã³ãã®èšå®ã«ããããç»é²ããå¿
èŠããããŸãã
./src/app.js partials: { ... homepage: require('./templates/parsed/homepage'), notfound: require('./templates/parsed/notfound') },
å®å
šãªã³ãŒã./src/app.js const Ractive = require('ractive'); Ractive.DEBUG = (process.env.NODE_ENV === 'development'); Ractive.DEBUG_PROMISES = Ractive.DEBUG; Ractive.defaults.enhance = true; Ractive.defaults.lazy = true; Ractive.defaults.sanitize = true; Ractive.defaults.data.formatDate = require('./helpers/formatDate'); Ractive.defaults.data.errors = null; Ractive.partials.errors = require('./templates/parsed/errors'); Ractive.use(require('ractive-ready')()); Ractive.use(require('ractive-page')({ meta: require('../config/meta.json') })); const api = require('./services/api'); const options = { el: '#app', template: require('./templates/parsed/app'), partials: { navbar: require('./templates/parsed/navbar'), footer: require('./templates/parsed/footer'), homepage: require('./templates/parsed/homepage'), notfound: require('./templates/parsed/notfound') }, transitions: { fade: require('ractive-transitions-fade'), } }; module.exports = () => new Ractive(options);
ãŸãããã©ã³ãžã·ã§ã³ã¢ãã¡ãŒã·ã§ã³ã®èšå®ãå°ã詊ããŸããã
ããŒãžããŒã·ã§ã³ã³ã³ããŒãã³ã
ãã®ã³ã³ããŒãã³ãã¯ãçŽç²ãªã³ã³ããŒãã³ãã®æãã代衚ã§ãã 圌ã®ä»äºã®çµæã¯ãå
¥åãã©ã¡ãŒã¿-ã³ã³ããŒãã³ã屿§ã«å®å
šã«åºã¥ããŠããŸãã

èŠèŠçã«ã¯ããã®ã³ã³ããŒãã³ãã¯å®å
šã«æšæºã«èŠããŸãããã©ã®
å¯äœçšãçæãããã®
å¯äœçšãã©ã®çšåºŠæ£ç¢ºã«å¶åŸ¡ããããæ±ºå®ããããšãéèŠã§ãã ååã®ã¢ããªã±ãŒã·ã§ã³ã®ã³ã³ããã¹ãã§ã¯ã挞é²çãªæ¹åã«ããããã®è³ªåã«å¯Ÿããçãã¯æçœã§ã-URLã倿ŽããŸãã
JSãç¡å¹ã«ãªã£ãŠããŠããããŒãžéãç§»åã§ããå¿
èŠãããããšãåžžã«èŠããŠããå¿
èŠããããŸãã ã€ãŸããåããŒãžã¯ç¬èªã®URLïŒãªã³ã¯ïŒã§è¡šãããå¿
èŠããããŸãã ããã«ããã©ãŠã¶ã§ããŒãžããªããŒããããšããéžæãããªã¹ãããŒãžã«ãšã©ãŸãå¿
èŠããããŸãïŒ
SSRã®å®å
šãµããŒãïŒã
ã¬ã€ãã©ã€ã³ã«ã¯ãããŒãžããŒã·ã§ã³ãURLã«ã©ã®ããã«åæ ãããã¹ãããããããŸã£ãããªããã©ããã«é¢ããæšå¥šäºé
ããªãããããªã¹ãã«ãªãã»ãããå«ã
URL Queryãã©ã¡ãŒã¿ãŒ
offsetã䜿çšã
ãŸã ã ãªã
ããŒãžã§ã¯ãªã
ãªãã»ããã§ããïŒ ããã¯APIã§ããŒãžããŒã·ã§ã³ãæ©èœããæ¹æ³ãªã®ã§ãããã¯ç°¡åã§ãã
?offset=20
ããŠãæåã®
Ractiveã³ã³ããŒãã³ããäœæããŸãã ãããè¡ãããã«ã
Ractiveã³ã³ã¹ãã©ã¯ã¿ãŒã¯éçãª
extendïŒïŒã¡ãœãããæäŸããŸããããã«ãããã³ã³ã¹ãã©ã¯ã¿ãŒãæ°ããããããã£ã§æ¡åŒµããæ¢åã®ããããã£ãäžæžãããŠãçµæãšããŠæ°ããã³ã³ã¹ãã©ã¯ã¿ãŒãååŸã§ããŸãã ç°¡åã«èšãã°ãããã¯ç¶æ¿ã§ãã
./src/components/Pagination.js const Ractive = require('ractive'); module.exports = Ractive.extend({ template: require('../templates/parsed/pagination'), attributes: { required: ['total'], optional: ['offset', 'limit'] }, data: () => ({ total: 0, limit: 10, offset: 0, isCurrent(page) { let limit = parseInt(this.get('limit')), offset = parseInt(this.get('offset')); return offset === ((page * limit) - limit); }, getOffset(page) { return (page - 1) * parseInt(this.get('limit')); } }), computed: { pages() { let length = Math.ceil(parseInt(this.get('total')) / parseInt(this.get('limit'))); return Array.apply(null, { length }).map((p, i) => ++i);; } } });
ãã®ã³ã³ããŒãã³ãã¯ã屿§
total ïŒãªã¹ãå
ã®èŠçŽ ã®ç·æ°ïŒã
limit ïŒããŒãžäžã®èŠçŽ ã®æ°ïŒãããã³
offset ïŒãªã¹ãå
ã®çŸåšã®ãªãã»ããïŒãåãå
¥ããŸãã ãããã®ããããã£ã«åºã¥ããŠãã³ã³ããŒãã³ãã¯ããŒãžã®ãªã¹ããçæããŸããããã¯ã
ããŒãžã®èšç®ãããããããã£ãšããŠå®è£
ãã
ãŸã ã ããã«ãäŸåããããã£ã®ãããããæéãšãšãã«å€åãããšãèšç®ãããããããã£ãèªåçã«åèšç®ãããŸãã 䟿å©ã«ã
./src/templates/pagination.html {{#if total > 0 && pages.length > 1}} <nav> <ul class="pagination"> {{#each pages as page}} <li class-active="isCurrent(page)" class="page-item"> <a href="?{{ @shared.$route.join('offset', getOffset(page)) }}" class="page-link"> {{ page }} </a> </li> {{/each}} </ul> </nav> {{/if}}
ãã³ãã¬ãŒãã§ã¯ããã®ãªã¹ãããªã³ã¯ãšããŠè¡šç€ºããã ãã§ãã ã«ãŒã¿ãŒã§ã®ç¹å¥ãª
joinïŒïŒã¡ãœããã®äœ¿çšã«æ³šæããŠãã ããã ãã®ã¡ãœããã¯ãæž¡ããããã©ã¡ãŒã¿ãŒãšãã®å€ãçŸåšã®
ã¯ãšãªURLãšããŒãžããŸãããã®çµæãæ¢åã®ã¯ãšãªæååãååŸããããã«ååšãããã©ã¡ãŒã¿ãŒãèæ
®ããŸãã ãã€ãã®ããã«ãã«ãŒã¿ãŒèªäœããªã³ã¯åŠçã«é¢ãããã¹ãŠã®äœæ¥ãåŒãåãããããå¿é
ããå¿
èŠã¯ãããŸããã
çµæã¯ããªãå°ããã·ã³ãã«ãªã³ã³ããŒãã³ãã§ããããã®å¯äžã®
å¯äœçšã¯URLãã©ã¡ãŒã¿ã®å€æŽã§ãã ããã«ãããä»»æã®ãªã¹ããå«ãã³ã³ããžã·ã§ã³ã§ãã®ã³ã³ããŒãã³ãã䜿çšã§ããŸãã ãªã¹ããå®è£
ããã³ã³ããŒãã³ãã¯ã察å¿ããURLãã©ã¡ãŒã¿ãŒã®å€æŽããµãã¹ã¯ã©ã€ããããã®å€ãAPIãªã¯ãšã¹ããšããŒã¿åºåã«äœ¿çšããŸãã
ã³ã³ããŒãã³ãã¿ã°
ãã®ã³ã³ããŒãã³ããçŽç²ã§ãã ãã ãã
ããŒãžããŒã·ã§ã³ãšã¯ç°ãªããããã«ã¯ç°ãªãåæããããŸãã

ãã®åçã¯ã
Tagsã³ã³ããŒãã³ããã¢ããªã±ãŒã·ã§ã³ã®å€ãã®å Žæã§å®éã«äœ¿çšãããŠããããšã瀺ããŠããŸãã ãã®ã³ã³ããŒãã³ããç¹å®ã®ã¿ã°ã®ãªã¹ãã§æ©èœããããšãæããã§ãã ããããæãéèŠãªããšã¯ãã¿ã°ã®ãªã¹ããã³ã³ããŒãã³ããå®è¡ãããã³ã³ããã¹ãã«äŸåããããšãããã«æããã«ãªãããšã§ãã ã¡ã€ã³ããŒãž-ããã¯èšäºã®ãªã¹ãå
ã®äººæ°ã®ããã¿ã°ã®ãªã¹ãã§ã-ãããã¯ç¹å®ã®èšäºã®ã¿ã°ãªã©ã§ãã ãã®ããããã®ã³ã³ããŒãã³ãã¯åçŽã«èªåŸçã§ã¯ãªãã䜿çšãããŠããã³ã³ããã¹ãããèšäºã®ãªã¹ãã転éããå¿
èŠããããŸãã
./src/components/Tags.js const Ractive = require('ractive'); module.exports = Ractive.extend({ template: require('../templates/parsed/tags'), attributes: { required: ['tags'], optional: ['skin'] }, data: () => ({ tags: [], skin: 'outline' }) });
./src/templates/tags.html {{#await tags}} <p>Loading...</p> {{then tags}} <ul class="tag-list"> {{#each tags as tag}} <li> <a href="/?tag={{ tag }}" class="tag-pill tag-default tag-{{~/skin}}"> {{ tag }} </a> </li> {{/each}} </ul> {{catch errors}} {{>errors}} {{else}} <p>No tags</p> {{/await}}
ãã®ã³ã³ããŒãã³ãã¯ããã«ã·ã³ãã«ã§ãã ã¿ã°ã¿ã°ã®ãªã¹ããšè¿œå ã®ãã©ã¡ãŒã¿
ã¹ãã³ -ã¹ã¿ã€ã«ã¿ã°ïŒ
outlineããã³fillïŒãåãå
¥ããŸãã
ã¿ã°ã¯ãã¿ã°ã®ãªã¹ããé
åãŸãã¯ãããã¹ãšããŠåãå
¥ããç¬ç«ããŠãããã¿ã°ãªã¹ãã«è§£æ±ºã§ããŸãã
Paginationãšåã
å¯äœçšãçæããŸã-ã¯ãšãªãã©ã¡ãŒã¿
ã¿ã°ã倿ŽããŸãïŒããã§ããã¬ã€ãã©ã€ã³ã«æšå¥šäºé
ã¯ãããŸããïŒã äŸåé¢ä¿ã¯ãªããã¢ããªã±ãŒã·ã§ã³ã®ã©ãã§ã䜿çšã§ããŸãã
å¯äœçšã«ã€ããŠããŒãžããŒã·ã§ã³ã³ã³ããŒãã³ããšã¯ç°ãªãããã®ã³ã³ããŒãã³ãã¯å€æ°ãã©ã¡ãŒã¿ãã¯ãšãªæååã®æ®ãã®éšåã«ããŒãžãããå®å
šã«æŽæ°ããããšã«ç¹ã«æ³šæãã䟡å€ããããŸãã å®éã«ã¯ãã¿ã°ãã¯ãªãã¯ãããšããŠãŒã¶ãŒã¯ãã®ã¿ã°ã«äžèŽããæŽæ°ãããèšäºã®ãªã¹ããèŠãããšãã§ããŸãã ãããã£ãŠãããŒãžããã²ãŒã·ã§ã³ãªã©ãåã®ãªã¹ãã§å¯èœãªæäœã¯ãŒãã«ãªã»ããããå¿
èŠããããŸãã ãã®å ŽåãããŒãžç·šéã³ã³ããŒãã³ãã¯æ¢åã®ã¯ãšãªæååã«å¯Ÿãããã©ã¡ãŒã¿ãŒãç¶æããããã ããŒãžç·šéã¯ã¿ã°ã®æ¹è¯ãšé£æºããŠæ©èœããŸãã
ã¡ã€ã³ããŒãžã§ãã®ã³ã³ããŒãã³ãã䜿çšããŠã¿ãŸãããã ãŸããAPIãã人æ°ã®ããã¿ã°ã®ãªã¹ããååŸããå¿
èŠããããŸãã ãã®ãããAPIã§åäœãããµãŒãã¹ã«ã¯æ¢ã«æ¢è£œã®åŒã³åºããããããã®èŠæ±ãå®è£
ããã³ãŒããèšè¿°ããã ãã§ãã
ãŸããåã®èšäºã§èª¬æããSSRããã³ä»ã®å圢ã®éšåã®ãµããŒããèŠããŠããããšãéåžžã«éèŠã§ãããããè峿·±ããã€ã³ãã§ããã»ãšãã©ã®å Žåãæ³šæãæã£ãŠèšç®ãããã³ã³ããŒãã³ãã®ããããã£ã®å©ããåããŠããã®ãããªããŒã¿ååŸèŠæ±ãå®è£
ããŸãïŒãªãã§ïŒ
Articlesããã³Profileã³ã³ããŒãã³ãã®äŸã§ãããçè§£ã§ãããšç¢ºä¿¡ããŠããŸããäžèšã§èšãã°-ããã¯ãããã«è¡ãã®ã¯çŽ æŽãããã§ãïŒãã®ãããå€ãè¿ãã ãã®åçŽãªé¢æ°ãäœæããŠããŸãïŒ./src / computed /tags.js const api = require('../services/api'); module.exports = function() { const key = 'tagsList', keychain = `${this.snapshot}${this.keychain()}.${key}`; let tags = this.get(keychain); if ( ! tags) { tags = api.tags.fetchAll().then(data => data.tags); this.wait(tags, key); } return tags; };
ã芧ã®ãšãããè€éãªããšã¯äœããããŸãããèšç®ãããããããã£ã®é¢æ°ã¯ãæ¥ç¶å
ã®ã³ã³ããŒãã³ãã®ã³ã³ããã¹ãã§å®è¡ãããŸããããã§èµ·ãããã¹ãŠã¯åã®éšåã§ãã§ã«èª¬æãããŸãããããã«ãæçµçã«ractive-readyãã©ã°ã€ã³ã®keychainïŒïŒã¡ãœããã䜿çšããŸããããã®ã¡ãœããã¯ããã®èšç®ãããããããã£ãæ¥ç¶ããã³ã³ããŒãã³ãã®ãã¹ãã¬ãã«ã«å¿ããŠãããŒã¿ãªããžã§ã¯ãå
ã®æ£ãããã¹ãåã«è¿ããŸããæ¬¡ã«ããã®ããããã£ãRootã³ã³ããŒãã³ãã«æ¥ç¶ããTagsã³ã³ããŒãã³ããæ¥ç¶ããŠããã®ããããã£ã屿§ãšããŠæž¡ããŸãã./src/app.js ... Ractive.defaults.snapshot = '@global.__DATA__'; ... components: { tags: require('./components/Tags'), }, computed: { tags: require('./computed/tags') }, ...
å®å
šãªã³ãŒã./src/app.js const Ractive = require('ractive'); Ractive.DEBUG = (process.env.NODE_ENV === 'development'); Ractive.DEBUG_PROMISES = Ractive.DEBUG; Ractive.defaults.enhance = true; Ractive.defaults.lazy = true; Ractive.defaults.sanitize = true; Ractive.defaults.snapshot = '@global.__DATA__'; Ractive.defaults.data.formatDate = require('./helpers/formatDate'); Ractive.defaults.data.errors = null; Ractive.partials.errors = require('./templates/parsed/errors'); Ractive.use(require('ractive-ready')()); Ractive.use(require('ractive-page')({ meta: require('../config/meta.json') })); const api = require('./services/api'); const options = { el: '#app', template: require('./templates/parsed/app'), partials: { navbar: require('./templates/parsed/navbar'), footer: require('./templates/parsed/footer'), homepage: require('./templates/parsed/homepage'), notfound: require('./templates/parsed/notfound') }, transitions: { fade: require('ractive-transitions-fade'), }, components: { tags: require('./components/Tags'), }, computed: { tags: require('./computed/tags') } }; module.exports = () => new Ractive(options);
./src/templates/partials/homepage.html ... <div class="sidebar"> <p>Popular Tags</p> <tags tags="{{ tags }}" skin="filled" /> </div> ...
å®å
šãªã³ãŒã./src/templates/partials/homepage.html <div class="banner"> <div class="container"> <h1 class="logo-font">conduit</h1> <p>A place to share your knowledge.</p> </div> </div> <div class="container page"> <div class="row"> <div class="col-md-9"> <div class="feed-toggle"> <ul class="nav nav-pills outline-active"> <li class="nav-item"> <a href="/" class-active="$route.pathname === '/'" class="nav-link"> Global Feed </a> </li> </ul> </div> Articles list </div> <div class="col-md-3"> <div class="sidebar"> <p>Popular Tags</p> <tags tags="{{ tags }}" skin="filled" /> </div> </div> </div> </div>
ããããã¹ãŠã§ãããæãéèŠãªããšã¯ãçµæãç®ã«å¿å°ããããšã§ããã¿ã°ã¯ãµãŒããŒã«ããŒããããTagsã³ã³ããŒãã³ãã¯SSRã®éã«ã¬ã³ããªã³ã°ãããŸããã¿ã°ã®ãªã¹ãã«ã¯åæããŒã¿ç¶æ
ãå«ãŸãããããã³ã³ããŒãã³ãã¯APIãžã®2çªç®ã®ãªã¯ãšã¹ããªãã§ã¯ã©ã€ã¢ã³ãäžã§æ£åžžã«æ°ŽåãããŸããã·ã£ã€ã³ïŒã³ã³ããŒãã³ãèšäº
ã¹ã¿ã³ãã¢ãã³ã³ã³ããŒãã³ããšã¯ãªãŒã³ã³ã³ããŒãã³ãã®äž»ãªéãã¯ãã¹ã¿ã³ãã¢ãã³ã³ã³ããŒãã³ããæ©èœããããã«ã¯ã芪ã³ã³ããŒãã³ãã«ãã©ã°ã€ã³ããé©åãªã¿ã°ãããŒã¯ã¢ããã«è¿œå ããã ãã§ããå¿
èŠã«å¿ããŠã屿§ãä»ããŠããã€ãã®èšå®ãæž¡ãããšãã§ããŸãããã®ãããªã³ã³ããŒãã³ããšããã«é¢é£ãããã¹ãŠã®æ©èœãåé€ãŸãã¯ç¡å¹ã«ããå¿
èŠãããå Žåãåãããšãæ©èœããŸãããã³ãã¬ãŒãã§ã®äœ¿çšã忢ãããã芪ã³ã³ããŒãã³ãããåé€ããã ãã§ããã¢ããªã±ãŒã·ã§ã³ã®ãã®ãããªã³ã³ããŒãã³ãã®1ã€ã¯Articlesã³ã³ããŒãã³ãã§ãããã®ã³ã³ããŒãã³ãã¯ãèšäºã®ãªã¹ãã®ãŸã£ããå¥ã®æ©èœãå®è£
ããTagsãPaginationãªã©ã®ä»ã®ã³ã³ããŒãã³ããå
éšçã«äœ¿çšããŸãã
ã³ã³ããŒãã³ãèšäº ã¢ããªã±ãŒã·ã§ã³ã®å°ãªããšã2ããŒãžïŒã¡ã€ã³ããã³ãããã¡ã€ã«ïŒã§äœ¿çšããã転éããããã©ã¡ãŒã¿ãŒã«å¿ããŠ5çš®é¡ã®èšäºãªã¹ãã衚瀺ã§ããŸãã- èšäºã®äžè¬çãªãªã¹ã
- çŸåšã®ãŠãŒã¶ãŒã®ãµãã¹ã¯ãªãã·ã§ã³ã«åºã¥ãèšäºã®å人çãªãªã¹ã
- äœããã®ã¿ã°ã«ãã£ã«ã¿ãŒãããèšäºã®ãªã¹ã
- ä»»æã®ãŠãŒã¶ãŒãäœæããèšäºã®ãªã¹ã
- ä»»æã®ãŠãŒã¶ãŒããæ°ã«å
¥ãã«è¿œå ããèšäºã®ãªã¹ã
ããïŒããã«ããããã®ãªã¹ãã¿ã€ãã¯ãã¹ãŠãããŒãžããŒã·ã§ã³ããµããŒãããå圢ã§ãããJSãªãã§æ©èœããå¿
èŠããããŸããå®éããã®ãããªç¶æ³ã§ã¯ãã¹ã¿ã³ãã¢ãã³ã³ã³ããŒãã³ããåªãããœãªã¥ãŒã·ã§ã³ã§ããå¿
èŠãªãã¹ãŠã®ããŒã¯ã¢ãããšããžãã¯ãã³ã³ããŒãã³ãå
ã«ã«ãã»ã«åããŠãå¿
èŠãªã€ã³ã¿ãŒãã§ã€ã¹ã®ã¿ãå
¬éã§ããŸããããã«ãããã¢ããªã±ãŒã·ã§ã³ã®ããŸããŸãªéšåã§ã³ã³ããŒãã³ãã䜿çšããéã®å±éºãªå¯äœçšããªããªããŸããããŒã¿ã®ååŸããå§ããŸãããïŒ./src / computed /articles.js const api = require('../services/api'); module.exports = function() { const type = this.get('type'), params = this.get('params'); const key = 'articlesList', keychain = `${this.snapshot}${this.keychain()}.${key}`; let articles = this.get(keychain); if (articles) { this.set(keychain, null); } else { articles = api.articles.fetchAll(type, params); this.wait(articles, key); } return articles; };
ã芧ã®ãšãããèšç®ããããã£çšã®é¢æ°ãååºŠäœæããŸããããã¿ã°ã®å Žåãšåãã§ãããã¿ãã¬ã®äžã§èšç®ãããããããã£ã®å©ç¹ã«ã€ããŠèªçºçã«ãèªã¿ãã ãããã¢ãããŒãã®å©ç¹, , . ?
-, , :
-, «» :
<!-- , --> {{#if baz}} {{foo}} {{/if}} <!-- , --> {{#if baz}} {{bar}} {{/if}}
-, :
-, ( ) . . :
computed: { foo: require('./computed/baz'), bar: require('./computed/baz'), }
, , , . , 10 -
Articles ⊠?
次ã«ãã³ã³ããŒãã³ãèªäœã«ã€ããŠèª¬æããŸãïŒ./src/ components/Articles.js const Ractive = require('ractive'); module.exports = Ractive.extend({ template: require('../templates/parsed/articles'), components: { pagination: require('./Pagination'), tags: require('./Tags'), }, computed: { articles: require('../computed/articles') }, attributes: { optional: ['type', 'params'] }, data: () => ({ type: '', params: null }) });
ããã§ããã¹ããããã³ã³ããŒãã³ããèšç®ãããããããã£ãæ¥ç¶ããã³ã³ããŒãã³ãã€ã³ã¿ãŒãã§ã€ã¹ã決å®ããŸããããªãã·ã§ã³ã®2ã€ã®å±æ§ã®ã¿ãåãå
¥ããŸãïŒtypeïŒãªã¹ãã¿ã€ããç©ºã®æååãŸã㯠'feed'ã®ããããïŒãšparamsïŒãã£ã«ã¿ãŒãã©ã¡ãŒã¿ãŒãæã€ãªããžã§ã¯ãïŒãå®éã«ã¯ã³ã³ããŒãã³ããå°ãããªãããããã³ãã¬ãŒãã¯å°ãè€éã«ãªããŸããïŒ./src / templates /articles.html <div class="articles-list"> {{#await articles}} <div class="article-preview"> <p>Loading articles...</p> </div> {{then data}} {{#each data.articles as article}} <div class="article-preview"> <div class="article-meta"> <a href="/profile/{{ article.author.username }}"> <img src="{{ article.author.image }}" /> </a> <div class="info"> <a href="/profile/{{ article.author.username }}" class="author"> {{ article.author.username }} </a> <span class="date">{{ formatDate(article.createdAt) }}</span> </div> </div> <a href="/article/{{ article.slug }}" class="preview-link"> <h1>{{ article.title }}</h1> <p>{{ article.description }}</p> <span>Read more...</span> <tags tags="{{ article.tagList }}"/> </a> </div> {{else}} <div class="article-preview"> <p>No articles are here... yet.</p> </div> {{/each}} <pagination total="{{ data.articlesCount }}" offset="{{ @shared.$route.query.offset || 0 }}" limit="20" /> {{catch errors}} <div class="article-preview"> {{>errors}} </div> {{else}} <div class="article-preview"> <p>No articles are here... yet.</p> </div> {{/await}} </div>
ããŠãã¡ã€ã³ããŒãžã§ãããåããŸãããã./src/app.js components: { ... articles: require('./components/Articles'), },
å®å
šãªã³ãŒã./src/app.js const Ractive = require('ractive'); Ractive.DEBUG = (process.env.NODE_ENV === 'development'); Ractive.DEBUG_PROMISES = Ractive.DEBUG; Ractive.defaults.enhance = true; Ractive.defaults.lazy = true; Ractive.defaults.sanitize = true; Ractive.defaults.snapshot = '@global.__DATA__'; Ractive.defaults.data.formatDate = require('./helpers/formatDate'); Ractive.defaults.data.errors = null; Ractive.partials.errors = require('./templates/parsed/errors'); Ractive.use(require('ractive-ready')()); Ractive.use(require('ractive-page')({ meta: require('../config/meta.json') })); const api = require('./services/api'); const options = { el: '#app', template: require('./templates/parsed/app'), partials: { navbar: require('./templates/parsed/navbar'), footer: require('./templates/parsed/footer'), homepage: require('./templates/parsed/homepage'), notfound: require('./templates/parsed/notfound') }, transitions: { fade: require('ractive-transitions-fade'), }, components: { tags: require('./components/Tags'), articles: require('./components/Articles'), }, computed: { tags: require('./computed/tags') } }; module.exports = () => new Ractive(options);
./src/templates/partials/homepage.html ... <li class="nav-item"> <a href="/" class-active="$route.pathname === '/' && ! $route.query.tag" class="nav-link"> Global Feed </a> </li> {{#if $route.query.tag }} <li class="nav-item"> <a class="nav-link active"> # {{ $route.query.tag }} </a> </li> {{/if}} ... <articles params="{{ $route.query }}"/> ...
å®å
šãªã³ãŒã./src/templates/partials/homepage.html <div class="banner"> <div class="container"> <h1 class="logo-font">conduit</h1> <p>A place to share your knowledge.</p> </div> </div> <div class="container page"> <div class="row"> <div class="col-md-9"> <div class="feed-toggle"> <ul class="nav nav-pills outline-active"> <li class="nav-item"> <a href="/" class-active="$route.pathname === '/' && ! $route.query.tag" class="nav-link"> Global Feed </a> </li> {{#if $route.query.tag }} <li class="nav-item"> <a class="nav-link active"> # {{ $route.query.tag }} </a> </li> {{/if}} </ul> </div> <articles params="{{ $route.query }}"/> </div> <div class="col-md-3"> <div class="sidebar"> <p>Popular Tags</p> <tags tags="{{ tags }}" skin="filled" /> </div> </div> </div> </div>
ãã£ã«ã¿ãªã³ã°ãå®è£
ãããã¿ã°ã®ååãæã€ã¿ãã远å ããå®è£
ãã©ã®ããã«å®è£
ããããã«æ³šç®ããŠãã ããããŠãŒã¶ãŒãã¿ã°ã³ã³ããŒãã³ãããã¿ã°ãã¯ãªãã¯ãããšïŒèšäºãŸãã¯äººæ°ã®ã¿ã°ã®ãªã¹ãããã¯é¢ä¿ãããŸããïŒãèšäºã®ãªã¹ãã¯ãã®ã¿ã°ã«ãã£ãŠãã£ã«ã¿ãŒãããã ãã§ãªããèŠèŠçã«åŒ·èª¿ããããã«ã¿ã°åã®ã¿ãã远å ãããŸããäžè¬ã«ãããã¯æ¬¡ã®ããã«æ©èœããç§ã®æèŠã§ã¯ãã²ã©ã倿ããŸããã§ããïŒãããŠãã¡ããããã¹ãŠãååã§ãããæåã®èªã¿èŸŒã¿ã¯ã¯ã©ã€ã¢ã³ãã§ã®åäžã®ajaxãªã¯ãšã¹ããªãã§çºçããŸãããã©ãŠã¶ã®å±¥æŽã¯å®å
šã«æ©èœããJSããªãã«ãããšããã¹ãŠãæ£åžžã«æ©èœããŸããèŠããã«ãããã«å
ã«é²ã¿ãŸãããããã¡ã€ã«ã³ã³ããŒãã³ã
ãã®ã³ã³ããŒãã³ãã¯ååºãããã®ã«ãªãã§ãããããããã§ã¯ãããŸãããããã¯ãArticlesãšåãã¹ã¿ã³ãã¢ãã³ã³ã³ããŒãã³ãã®ãã©ã¹ãŸãã¯ãã€ãã¹ã§ããããã©ã¹ãŸãã¯ãã€ãã¹ã§ãæ©èœããŸããå®éã1ããŒãžã§ãã䜿çšãããªããããããã«éå±ã§ãã
å®éã圌ã¯ãã®ããŒãžã§ããå¥ã®èšãæ¹ãç¥ããŸããã./src/components/Profile.js const Ractive = require('ractive'); module.exports = Ractive.extend({ template: require('../templates/parsed/profile'), components: { articles: require('./Articles') }, computed: { profile: require('../computed/profile') }, attributes: { required: ['username'], optional: ['section'] }, data: () => ({ username: '', section: '' }) });
ãã ããåŸæ¥ã®èšç®ããããã£ã¯ãŸã å°ãè€éã§ãïŒ./src / computed /profile.js const api = require('../services/api'); let _profile; module.exports = function() { const username = this.get('username'); const key = 'profileData', keychain = `${this.root.snapshot}${this.keychain()}.${key}`; let profile = this.get(keychain); if (profile) { this.set(keychain, null); _profile = profile; } else if (_profile && _profile.username === username) { profile = _profile; } else if (username) { profile = api.profiles.fetch(username).then(data => (_profile = data.profile, _profile)); this.wait(profile, key); } return profile; };
ãæ°ã«å
¥ãã®èšäºã®ãµãã«ãŒãã«åãæ¿ãããšãããŸãã¯ãã®éã«åãæ¿ãããšãã«ãŠãŒã¶ãŒãããã¡ã€ã«ãååºŠèŠæ±ããããªãã®ã§ãããã§ã¯ããŒãžã£ãŒã®ãŠãŒã¶ãŒãããã¡ã€ã«ïŒ_profileïŒãããã£ãã·ã¥ãããŠããŸããé£ããã¯ãªããé«äŸ¡ã§ããããŸããããããŸãæ©èœããŸããããšãã°ãReact / Reduxã®å®è£
ã§ã¯ããã®åé¡ã¯è§£æ±ºãããªãããããMy ArticlesããšãFavorited Articlesããåãæ¿ãããã³ã«ãããã¡ã€ã«ãååŸãããŸããããã«åœŒãã詊ã¿ãªãã£ãããšã¯æããã§ããããã§ããã³ãã¬ãŒãã§ãã®ãšã³ãããŒããã¹ãŠäœ¿çšããŸãïŒ./src/ templates/profile.html <div class="profile"> {{#await profile}} {{then profile}} <div class="user-info"> <div class="container"> <div class="row"> <div class="col-xs-12 col-md-10 offset-md-1"> <img src="{{ profile.image }}" class="user-img" /> <h4>{{ profile.username }}</h4> <p>{{ profile.bio }}</p> </div> </div> </div> </div> {{catch errors}} {{>errors}} {{/await}} {{#if username}} <div class="container"> <div class="row"> <div class="col-xs-12 col-md-10 offset-md-1"> <div class="articles-toggle"> <ul class="nav nav-pills outline-active"> <li class="nav-item"> <a href="/profile/{{ username }}" class-active="! section" class="nav-link"> My Articles </a> </li> <li class="nav-item"> <a href="/profile/{{ username }}/favorites" class-active="section === 'favorites'" class="nav-link"> Favorited Articles </a> </li> </ul> </div> <articles params="{{ section === 'favorites' ? {favorited: username} : {author: username} }}" /> </div> </div> </div> {{/if}} </div>
ãã®åŸããã¹ãŠãéåžžéãã§ã- ã«ãŒãã³ã³ããŒãã³ããšå¯Ÿå¿ããã«ãŒãã«è¿œå ããŸãã./src/app.js components: { ... profile: require('./components/Profile'), },
å®å
šãªã³ãŒã./src/app.js const Ractive = require('ractive'); Ractive.DEBUG = (process.env.NODE_ENV === 'development'); Ractive.DEBUG_PROMISES = Ractive.DEBUG; Ractive.defaults.enhance = true; Ractive.defaults.lazy = true; Ractive.defaults.sanitize = true; Ractive.defaults.snapshot = '@global.__DATA__'; Ractive.defaults.data.formatDate = require('./helpers/formatDate'); Ractive.defaults.data.errors = null; Ractive.partials.errors = require('./templates/parsed/errors'); Ractive.use(require('ractive-ready')()); Ractive.use(require('ractive-page')({ meta: require('../config/meta.json') })); const api = require('./services/api'); const options = { el: '#app', template: require('./templates/parsed/app'), partials: { navbar: require('./templates/parsed/navbar'), footer: require('./templates/parsed/footer'), homepage: require('./templates/parsed/homepage'), notfound: require('./templates/parsed/notfound') }, transitions: { fade: require('ractive-transitions-fade'), }, components: { tags: require('./components/Tags'), articles: require('./components/Articles'), profile: require('./components/Profile'), }, computed: { tags: require('./computed/tags') } }; module.exports = () => new Ractive(options);
./src/templates/app.html ... {{elseif $route.match('/profile/:username/:section?') }} <div class="profile-page" fade-in="fadeIn" fade-out="fadeOut"> <profile username="{{ $route.params.username }}" section="{{ $route.params.section }}" /> </div> ...
å®å
šãªã³ãŒã./src/templates/app.html {{>navbar}} {{#with @shared.$route as $route, {delay: 500} as fadeIn, {duration: 200} as fadeOut }} <div class="page"> {{#if $route.match('/login') }} <div class="auth-page" fade-in="fadeIn" fade-out="fadeOut"> Login page </div> {{elseif $route.match('/register') }} <div class="auth-page" fade-in="fadeIn" fade-out="fadeOut"> Register page </div> {{elseif $route.match('/profile/:username/:section?') }} <div class="profile-page" fade-in="fadeIn" fade-out="fadeOut"> <profile username="{{ $route.params.username }}" section="{{ $route.params.section }}" /> </div> {{elseif $route.match('/') }} <div class="home-page" fade-in="fadeIn" fade-out="fadeOut"> {{>homepage}} </div> {{else}} <div class="notfound-page" fade-in="fadeIn" fade-out="fadeOut"> {{>notfound}} </div> {{/if}} </div> {{/with}} {{>footer}}
ãã¶ãã仿¥ã¯ããã§ååã§ããããçŸåšã®ãããžã§ã¯ãã®çµæã¯ãã¡ãïŒâ
ãªããžããªâ ãã¢æ¬¡ã®ããŒãã§ã¯ãæ¿èªãšååãã©ãŒã ãæ®µéçã«åŒ·åããŠãããŸããé¢çœãã§ããããåãæ¿ããªãã§ãã ããïŒ