
ä»å¹Žã®åãã«ãHeadHunterã§ã¯ãã¯ã©ã€ã¢ã³ãäŒæ¥ã§ã®ããŸããŸãªHRããã»ã¹ã®èªååãç®çãšãããããžã§ã¯ããéå§ããŸããã åé¢ã®ãã®ãããžã§ã¯ãã®ã¢ãŒããã¯ãã£ã¯ãReact-Reduxã¹ã¿ãã¯ã§ããã
9ãæéã圌ã¯åŸæ¥å¡ããã¹ãããããã®å°ããªã¢ããªã±ãŒã·ã§ã³ããã仿¥ã§ã¯
ãæèœè©äŸ¡ããšåŒã°ãããã«ãã¢ãžã¥ãŒã«ãããžã§ã¯ãã«æé·ããŸããã æé·ããã«ã€ããŠã次ã®è³ªåã«çŽé¢ããŸããã
- ç¶æ
ã¹ãã¬ãŒãžããã®æ£èŠå;
- ãããžã§ã¯ãã®ã¹ã±ãŒã©ãã«ãªã¢ãŒããã¯ãã£ã䟿å©ãªéå±€ã®æ§ç¯-æ§é ãšããžãã¹ããžãã¯ã®äž¡æ¹ã
ããã¯ãã³ã³ããŒãã³ããã¬ãã¥ãŒãµãŒã®ã¢ãŒããã¯ãã£ãžã®ã¢ãããŒãã®å€æŽã«çŸããŸããã
ãããžã§ã¯ããã©ã®ããã«éçºããã©ã®ãããªæ±ºå®ãäžãããã«ã€ããŠè©±ããŸãããã ãããã®ããã€ãã¯ããholivnyãã§ããããšã倿ãããããããŸããããä»ã®äººã¯ãå察ã«ãreduxã§å€§èŠæš¡ãªãããžã§ã¯ããæ§ç¯ããéã®ãã¯ã©ã·ãã¯ãã§ãã 以äžã«èª¬æãããã©ã¯ãã£ã¹ããreact-reduxã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããéã«åœ¹ç«ã€ããšãæã¿ãå®éã®äŸãããã®ã¢ãããŒããŸãã¯ãã®ã¢ãããŒãã®ä»çµã¿ãçè§£ããã®ã«åœ¹ç«ã€ããšãé¡ã£ãŠããŸãã
äžè¬çãªæ
å ±ã ã€ã³ããã
Webã¢ããªã±ãŒã·ã§ã³ã¯SPAã§ãã ã¯ã©ã€ã¢ã³ãã§ã®ã¿ã¢ããªã±ãŒã·ã§ã³ãã¬ã³ããªã³ã°ããïŒä»¥äžã§çç±ã説æããŸãïŒã éçºã§ã¯ãReact-reduxã¹ã¿ãã¯ãããŸããŸãªããã«ãŠã§ã¢ãããšãã°redux-thunkãšãšãã«äœ¿çšããŸããã ãã®ãããžã§ã¯ãã§ã¯ãã¢ã»ã³ããªäžã«babelã§ã³ã³ãã€ã«ããães6ã䜿çšããŸãã éçºã¯ães7ã䜿çšããã«å®è¡ãããŸããããã¯ãæšæºã§ã¯åãå
¥ããããªããœãªã¥ãŒã·ã§ã³ãæ¡çšããããªãããã§ãã
ãããžã§ã¯ãã¯
test.hh.ruã§éšåçã«å©çšå¯èœã§ãããhhã«ç»é²ãããäŒç€Ÿã§ã®ã¿äœ¿çšã§ããŸãã
ãããžã§ã¯ãæ§é
ãããžã§ã¯ãã®æ§é ãšããŠãæåã«ã¢ããªã±ãŒã·ã§ã³ãããã€ãã®éšåã«åããŸããã çµæã¯ããã®ã¹ã¿ãã¯ã®ãå€å
žçãªãæ§é ã«ãªããŸããã
ããã«ïŒ
- ã¢ã¯ã·ã§ã³ã¯ããããžã§ã¯ãã®ãã¹ãŠã®ã¢ã¯ã·ã§ã³äœæè
ãä¿åãã責任ããããŸãã
- ã³ã³ããŒãã³ã-ãã¹ãŠã®ã³ã³ããŒãã³ããåå¿ããŸãã
- 宿°ã¯å®æ°ã§ãã ãã®ãã©ã«ãã§ã¯ã
ENTER_KEY = 13
ãããªå®æ°ã ãã§ãªããããŸããŸãªã¢ã¯ã·ã§ã³åãåéããããšãéèŠã§ããããšãã°ïŒ
export const FETCH_ACCOUNT = 'FETCH_ACCOUNT'; export const RECEIVE_ACCOUNT = 'RECEIVE_ACCOUNT';
ããã¯ãè¡ãçµããã«ã€ã³ããŒãã®äŸåé¢ä¿ãç°¡åã«ç¢ºèªã§ããããã«ããããã§ãã
ç¹å®ã®ã³ã³ããŒãã³ãã«ã®ã¿é¢é£ãã宿°ã¯èš±å®¹ããŸããã äŸïŒã³ã³ããã®äžéšå¢çç·ãããã¯ã»ã«åäœã§ã®è·é¢ãå°éãããšãæ°ããããŒã¿ãããŒããããŸãïŒã€ãŸããç¡éã¹ã¯ããŒã«ïŒã
- ã³ã³ããã¯ç¹å®ã®ãã£ã¬ã¯ããªã§ãã å¿
èŠã«å¿ããŠïŒããšãã°ãããŒã¿ã®äžè¶³ãªã©ïŒã¢ã¯ã·ã§ã³äœæè
ãåŒã³åºããã¬ã³ããªã³ã°ã®ããã«ã³ã³ããŒãã³ããéä¿¡ããããŒãžã³ã³ããŒãã³ãã§æ§æãããŸãã åæ§ã®ããŒãžã³ã³ããŒãã³ãã«å ããŠããã©ã«ãã«ã¯ããŸããŸãªãã³ã¬ãŒã¿/ãã¡ãµãŒããå«ãŸããŠããŸãã ãã®ãããªãã³ã¬ãŒã¿ãšã¯äœã§ããïŒ ãããè¡ãã«ã¯ãã³ã³ããã®1ã€ã®ã³ãŒããåæããŸãã
import React, { Component } from 'react'; import { connect } from 'react-redux'; import { compose } from 'redux'; import Content from '../components/content/content'; import Managers from '../components/managers/managers'; import composeRestricted from './restricted/restricted'; import { loadManagers } from '../actions/managers'; import title from './title/title'; class ManagersPage extends Component { componentWillMount() { if (!this.props.firstLoad) { this.props.loadManagers(this.props.location); } } render() { return ( <div className='page'> <Content> <Managers /> </Content> </div> ); } } export default compose( connect( state => state.location, {loadManagers} ), title('managers', 'title.base'), composeRestricted({user: true}) )(ManagersPage);
ããã§ã¯ããšã¯ã¹ããŒãã¢ãžã¥ãŒã«ã«ã€ããŠèª¬æããäžéšã«èå³ããããŸãã connectã¯æšæºã®react-reduxãã³ã¬ãŒã¿ã§ãã ã³ã³ããŒãã³ãã远å ã®ãªã¢ã¯ã·ã§ã³ã³ã³ããŒãã³ãã«ã©ããããŸããããã¯ãã¹ãã¢ã®ã°ããŒãã«ãªreduxç¶æ
ã®å€æŽããµãã¹ã¯ã©ã€ãããå Žæãã£ãŒã«ããæž¡ããŸãïŒããã«ãã¹ãã¢ã®ãã£ã¹ãããã§ã¢ã¯ã·ã§ã³ã¯ãªãšãŒã¿ãŒã®loadManagersãã©ããããŸãïŒã TitleãcomposeRestricted-ã³ã³ããŒãã³ããåãæ¹æ³ã§ã©ããããç¬èªã®ãã³ã¬ãŒã¿ã ããã§ã¿ã€ãã«ã¯èŠåºãã远å ããŸãã 2çªç®ã®ãã³ã¬ãŒã¿-composeRestricted-ã¯ããŠãŒã¶ãŒæš©éãæ±ºå®ããããã¯ãšã³ãã察å¿ãããšã©ãŒãéä¿¡ããå Žåã«å¶éãããããŒãžãã¬ã³ããªã³ã°ããŸããããšãã°ãæš©éããªãããŸãã¯ããŒã¿ããããŸããã ãã®ãããªãã³ã¬ãŒã¿ã¯å€æ°ååšããå¯èœæ§ããããŸãããäœããããŸããããªãã£ããã远å ã®èšç®ãªã©ã§ãã
- ã¬ãã¥ãŒãµãŒ-é¢çœããªããã¢ããªã±ãŒã·ã§ã³ã®ç¶æ
ã管çããã ã;ïŒã ãã«ãŒããã¬ãã¥ãŒãµãŒã¯ããã«æ ŒçŽãããä»ã®ãã¹ãŠãçµåããŸãïŒcombinedReducersã䜿çšïŒã
- store-ã¹ãã¢èšå®ããã®åæå;
- index.jsã¯ãã¢ããªã±ãŒã·ã§ã³ãžã®ãšã³ããªãã€ã³ãã§ãã åå¿ã®åæåãã«ãŒãã£ã³ã°ã®èª¬æãã¹ãã¬ãŒãžã®äœæãªã©ã
ãã®æ§é ã«ããããããžã§ã¯ãã®éçºãéå§ããŸããã ã·ã¹ãã ã®ãã¹ãŠã®èŠä»¶ãšãéçºããã»ã¹äžã«çºçããå¯èœæ§ã®ãããã¹ãŠã®å°é£ãäºåã«äºæž¬ããããšã¯äžå¯èœã§ãã ãããã£ãŠããããžã§ã¯ãã®æŒžé²çãªè¿ä»£åã®éãéžæããŸããã æ¬¡ã®ããã«æ©èœããŸãã
- ç¹å®ã®ã¢ããªã±ãŒã·ã§ã³ã¢ãã«ãéžæããŸãã
- äžéšã®ã¢ãããŒãã§ã¯åé¡ãåžæã©ããã«è§£æ±ºã§ããªããšããäºå®ã«çŽé¢ããŠããŸãã
- ãªãã¡ã¯ã¿ãªã³ã°ãå®è¡ããã¢ããªã±ãŒã·ã§ã³ã®æ§é ã倿ŽããŸãã
æéã®çµéã«äŒŽãã¢ããªã±ãŒã·ã§ã³ã®æ§é ã®å€åãåæããŠã¿ãŸãããã
æ§é ã®æ§ç¯ã å¹Œå°æ
ãããžã§ã¯ããè¥ãã倿°ã®ãã¡ã€ã«ã§å€§ãããªããããŠããªãå Žåã¯ãåçŽãªæ§ç¯ã¢ãã«ãéžæããããšããå§ãããŸãã ããã¯ãŸãã«ç§ãã¡ããã£ãããšã§ãã
ãã¹ãŠã®ã¢ã¯ã·ã§ã³ã¯ãªãšãŒã¿ãŒã¯ãååã«åŸã£ãŠæ ŒçŽãããŠããŸãããã€ãŸãã1ã€ã®ã°ã«ãŒãã®æäœãã€ãŸã1ã€ã®ãã¡ã€ã«ã«ãŸãšããããŠããŸãã ãã¹ãŠã®ãã¡ã€ã«ã¯ããã©ã«ããŒå
ã®1ã€ã®ãªã¹ãã«ä¿åãããŠããŸããã
ãã®ããã«èŠããïŒ
ã1ã€ã®æäœã°ã«ãŒãããšã¯äœã§ããïŒ 1ã€ã®ã¢ã¯ã·ã§ã³äœæè
ãã¡ã€ã«ãã1ã€ã®ã¬ãã¥ãŒãµãŒå
ã®ã¢ã¯ã·ã§ã³ãæ
åœããŠãããšèšããŸãã ãã®å Žåãã¢ã¯ã·ã§ã³ã®äœæè
ãšãªãã¥ãŒãµãŒã®ååã¯åãã§ããã100ïŒ
ã®ã±ãŒã¹ã§ã¯çºçããŸããã æå³ã§ã¯ããããã¯1ã€ã®ã¿ã€ãã®ãªããžã§ã¯ãã«å¯Ÿããæäœã§ãã ããšãã°ãemployee.jsã«ã¯ãç¹å®ã®ãªããžã§ã¯ãïŒãåŸæ¥å¡ãïŒãæäœããããã®ããŸããŸãªã¡ãœãããå«ãŸããŠããŸãã ããã¯åœŒã«é¢ããæ
å ±ã®ååŸãããŒã¿ã®èªã¿èŸŒã¿ãšã©ãŒã®åŠçãããŒã¿ã®å€æŽãæ°ããåŸæ¥å¡ã®è¿œå ã§ãã
ãã®ãããªæäœã®å
žåçãªã³ãŒãïŒ
export function loadEmployee(id) { return dispatch => {
ãã®ã³ãŒãã§ã¯ããµãŒããŒåŽãšã¬ãã¥ãŒãµãŒã®åäœãšã³ã³ããŒãã³ãã®åå¿ã®äž¡æ¹ã§ãäžåºŠã®ãã£ããã§ãšã©ãŒã®ã°ã«ãŒããäžåºŠã«åŠçããããšã«æ³šæããããšãéèŠã§ãã ãã詳现ã«ã¯ããã®ãããªã¢ãŒããã¯ãã£ãäœæããããšã«ããçç±ã¯ãèšäºã®æåŸã«ãããããŸããªãœãªã¥ãŒã·ã§ã³ã®ã»ã¯ã·ã§ã³ã«ãããŸãã
åæ§ã®ãã«ãã¢ãã«ãã¬ãã¥ãŒãµãŒãã³ã³ãããŒãããã³ã³ã³ããŒãã³ãã«æ¡çšãããŸããã ã³ã³ããŒãã³ãã®ãæ
£ç¿ãã¯ãããããã§ãã åã³ã³ããŒãã³ãã¯åå¥ã®ãã©ã«ããŒã«ãããŸãã ããã«ããã.jsã¢ãžã¥ãŒã«ãšã¹ã¿ã€ã«ã®äž¡æ¹ãé
眮ã§ããŸãããŸããå Žåã«ãã£ãŠã¯ããã©ã«ããŒå
ã«ç»åãšãã®ä»ã®ããŒã¿ãé
眮ããããšãã§ããŸãã
ææ¥æ
ãã®æ§é ã¯ãæåã®ã¢ãžã¥ãŒã«ã®äœæ¥ãçµäºãããŸã§æ£ç¢ºã«åç¶ããŸããã æ°ããã¢ãžã¥ãŒã«ã«ç§»ãåã«ãçµæã®ã³ã³ããŒãã³ãã®ã»ãããå·éã«èŠãŠãã·ã¹ãã ã®å¢å ã«äŒŽãããããžã§ã¯ãæ§é ã«å¯Ÿãããã®ã¢ãããŒãã¯æ··ä¹±ãæãã1ã€ã®ã·ã¹ãã ã¬ãã«ã«èšå€§ãªæ°ã®ãã¡ã€ã«ãååšããããšã«ãªããŸãã ããã«ããã¹ãŠã®jsã1ã€ã®ãã¡ã€ã«ã§ã¯ãªãåé¢ã«éä¿¡ããããšã«ããå ŽåïŒããšãã°ãjsãã³ãã«ã®ãµã€ãºãã¡ã¬ãã€ãåäœã®minifaen-aglipheneæ
å ±ã§å¢å ããå ŽåïŒããããããã€ãã®ãã³ãã«ã§ããã¹ãŠã®ã¢ãžã¥ãŒã«ã®äŸåé¢ä¿ãããªãé·ãé解決ããå¿
èŠããããŸãã
ãã®ãããæ¬¡ã®æ±ºå®ãäžããŸããïŒ2ã€ã®ã¢ãžã¥ãŒã«AãšBã«ã€ããŠèª¬æããŸãããä»»æã®æ°ã«ã¹ã±ãŒãªã³ã°ã§ããŸãïŒã
- ãã¹ãŠã®ã¢ã¯ã·ã§ã³ã¯ãªãšãŒã¿ãŒãã¬ãã¥ãŒãµãŒãããã³ã³ã³ãããŒã¯ã3ã€ã®ã¿ã€ãïŒcommonãmoduleAãmoduleBïŒã«åé¡ãããŸãã
- ã¢ã¯ã·ã§ã³ã¿ã€ããèšè¿°ããªã宿°ã¯ãã¹ãŠãconstantsãã©ã«ããŒå
ã«ãããŸãã åããã©ã«ããŒã«ã¯ãå¿
èŠãªã¢ã¯ã·ã§ã³ã®çš®é¡ã説æããã¢ã¯ã·ã§ã³ãã£ã¬ã¯ããªãå«ãŸããŠããŸãã ããã«ããããã¯2ã€ã®ã¿ã€ãã«åããããŸãã
- ã³ã³ããŒãã³ãã¯4ã€ã®ã¿ã€ãã«åããããŸãã
common-äžè¬çãªåå¿ã¢ãžã¥ãŒã«ãå«ãŸããŸãã ãããã¯ãããŒã®åå¿ã³ã³ããŒãã³ãã衚ããŸãïŒã€ãŸããUIãèšè¿°ããã³ã³ããŒãã³ãã®ã¿ããããå¶åŸ¡ãããã¢ããªã±ãŒã·ã§ã³ã®ç¶æ
ã«çŽæ¥äŸåãããã¢ã¯ã·ã§ã³ãåŒã³åºããŸããïŒãå®éã«ã¯ããããã¯ã¢ããªã±ãŒã·ã§ã³ã®ã©ãã§ã䜿çšãããã³ã³ããŒãã³ãã§ãã
ãããã¯-ã¢ããªã±ãŒã·ã§ã³ã®å
šäœçãªç¶æ
ã«äŸåããã³ã³ããŒãã³ãã ããšãã°ããããã¯ãéç¥ããŸãã¯ãéç¥ãã
moduleAãmoduleB-ã¢ãžã¥ãŒã«ã®ç¹å®ã®ã³ã³ããŒãã³ãã
ãããã¯ãšã¢ãžã¥ãŒã«ã¯ã©ã¡ããã¹ããŒãã³ã³ããŒãã³ãã§ããå¯èœæ§ããããäœããã®ã¢ã¯ã·ã§ã³ãåŒãèµ·ãããªã©
åãå
¥ããããèŠåã«ãããã¢ããªã±ãŒã·ã§ã³æ§é ã¯æ¬¡ã®ããã«ãªãå§ããŸããã
ãããã£ãŠããããžã§ã¯ãã®ã¢ãžã¥ãŒã«ã®æ¬è³ªã説æããæç¢ºãªæ§é ãåŸãŸãããããã§ã¯ãjsãã¡ã€ã«ãš1ã€ãŸãã¯å¥ã®ã¢ãžã¥ãŒã«ã®æ¯çãç°¡åã«æ±ºå®ã§ããŸããã€ãŸããã¢ãžã¥ãŒã«ã«ç°ãªããã³ãã«ãäœæããããšã決å®ããå Žåãããã¯é£ãããããŸããïŒã¡ããã©ãå¿
èŠãªéšåãžã®Webpackãã
ã¢ããªã±ãŒã·ã§ã³ç¶æ
ã®ã¢ãžã¥ãŒã«ãžã®åé¢
ããŠãç§ãã¡ã¯ãã¡ã€ã«ãæ§é çã«åå²ããŸããããç®ã¯åã¶ã§ãããããããžãã¯ãã¬ãã¥ãŒãµãŒã®ã¬ãã«ã§ã®ãã«ãã¢ãžã¥ãŒã«æ§é ã®ãµããŒãã«ã€ããŠã¯ã©ãã§ããããïŒ
å°èŠæš¡ãªã¢ããªã±ãŒã·ã§ã³ã®å Žåãã«ãŒãã¬ãã¥ãŒãµãŒã®èª¬æã¯é垞次ã®ãšããã§ãã
export const createReducer = () => { return combineReducers({ account, location, records, managers, tooltip, validation, progress, restrictedData, command, translations, status, features, module, settings, menu, routing: routeReducer, }); };
å°èŠæš¡ãªã¢ããªã±ãŒã·ã§ã³ã®å Žåããã¹ãŠã®ããŒã¿ãåçŽãªã³ã¬ã¯ã·ã§ã³ã«ãããããããã¯äŸ¿å©ã§ãã ããããã¢ããªã±ãŒã·ã§ã³ã®ãµã€ãºãå¢å ãããšã転éãããããŒã¿ã®æ°ãå¢å ãããããã¬ãã¥ãŒãµãŒãç²ç ããŠã¢ãžã¥ãŒã«ã«åå²ããå¿
èŠããããŸãã ãããã©ã®ããã«è¡ãããšãã§ããŸããïŒ çµæã«ç§»ãåã«ã2ã€ã®ç¶æ³ãæ€èšããŸãã
æåã®ç¶æ³ïŒããªããžã§ã¯ããåã
ã®æžéæ©ã«ç²ç ããã
åŸæ¥å¡ãšã³ãã£ãã£ããããšããŸãã ãã®ãšã³ãã£ãã£ã¯ãããŸããŸãªç¶æ³ãåæããæææ±ºå®ãèšè¿°ããã®ã«æé©ã§ãã ãšã³ãã£ãã£ãåŸæ¥å¡ãã䜿çšããŠãäŒç€Ÿã®ãããŒãžã£ãŒã¯ããŸããŸãªã¢ã¯ã·ã§ã³ãå®è¡ã§ããŸããã¢ããããŒããç·šéãäœæããã¹ããžã®æåŸ
ããã¹ãçµæã®è¡šç€ºã ãã®ãã£ãŒã«ãã¯ãã¹ããŒã¿ã¹ãšããŒã¿ã®2ã€ã®ãã£ãŒã«ããæã€ãªããžã§ã¯ãã§ãã statusã¯ããã£ãŒã«ãã®çŸåšã®ç¶æ
ïŒFETCH \ COMPLETE \ FAILïŒãããã³ããŒã¿-æçšãªããŒã¿ãåŸæ¥å¡ã®é
åãæ±ºå®ããŸãã ããã¯ããµãŒããŒããããŒã¿ãååŸããåŸæ¥å¡ã®ãªã¹ãã衚瀺ããã®ã«ååã§ãã
次ã«ãåŸæ¥å¡ãéžæããæ©èœã远å ããå¿
èŠããããŸãã
ãã®åé¡ã解決ããã«ã¯ã次ã®3ã€ã®æ¹æ³ããããŸãã
æ¹æ³1ïŒ
employees.dataé
åå
ã®èŠçŽ ã倿ŽããŠãidãnameãsurnameãpositionã«å ããŠãåèŠçŽ ã«éžæãããã£ãŒã«ããå«ãŸããããã«ããŸãã ãã§ãã¯ããã¯ã¹ãã¬ã³ããªã³ã°ãããšãããã®ãã£ãŒã«ããèŠãŠãããšãã°æ¬¡ã®ããã«åèšéé¡ãèæ
®ããŸãã
employees.data.reduce((employee, memo) => employee.selected ? memo + 1 : memo, 0);
å°æ¥ãéžæããIDãéä¿¡ããå¿
èŠãããå Žåããããã¯ãã¹ãŠåããã£ã«ã¿ãŒãä»ããŠæ€åºãããŸãã éžæãããã®ã®è¿œå /åé€ã¯ãããããä»ããŠåæ§ã«è¡ãããŸãã ãã®æ¹æ³ã®å©ç¹ã¯ãããŒã¿ãäžå
çã«ä¿åãããããšã§ãã æ¬ ç¹ã¯ãããããã¿ãããšã«ãªããžã§ã¯ãå
šäœã«è§Šããããšã§ãïŒéžæãããã©ã°ã远å /åé€ããŸãïŒã ããã«ãããããªãã®æ°ã®ã¢ã¯ã·ã§ã³ãçºçããŸãã éžæããåŸæ¥å¡ãšé£æºããããã®ããžãã¯ããåŸæ¥å¡åæžè
ãã¢ã¯ã·ã§ã³äœæè
ã«è¿œå ãããŸãã ãããã®éšåãåé¢ãããå ŽåïŒéžæããåŸæ¥å¡ãšé£æºããŠãåŸæ¥å¡åæžè
ã®ã¡ã€ã³ã¿ã¹ã¯ã«åœ±é¿ããªããããåŸæ¥å¡ãåé€ããŠããŒãžããŒã·ã§ã³ãè¡ãïŒãä»ã®2ã€ã®æ¹æ³ãæ€èšããå¿
èŠããããŸãã
2çªç®ã®æ¹æ³ïŒ
selectedEmployees
ãªã©ã®å¥ã®ã¬ãã¥ãŒãµãŒãäœæããŸãã ããã¯äžå€ã®ãããã§ããïŒå¿
èŠã«å¿ããŠããªããžã§ã¯ãã®ã¿ãé
åã§ããŸãïŒãéžæããIDã®ã¿ãæ ŒçŽããŸãã ãã®æ§é ã«idã远å ããã³åé€ãããšãã¯ããã«ç°¡åã«èŠããŸãã ãã§ãã¯ããã¯ã¹ã®ã¬ã³ããªã³ã°ã¯ããã¹
store.selectedEmployees.has(id)
ã«åŸãå¿
èŠããããšããäºå®ã«ãã£ãŠã®ã¿è€éã«ãªããŸãã ãããã£ãŠãéžæããåŸæ¥å¡ãšã®ãã¹ãŠã®äœæ¥ã¯ãå¥åã®ã¬ãã¥ãŒãµãŒãå¥åã®ã¢ã¯ã·ã§ã³ã°ã«ãŒãã«éãããŸãã
ãã®ãœãªã¥ãŒã·ã§ã³ã¯ãç¶æ
ã®ä»ã®éšåã倿Žããã³ããŒããããè¿ãã«å¥ã®éšåã远å ãããšããç¹ã§åªããŠããŸãã ãããã£ãŠãã¢ããªã±ãŒã·ã§ã³ãããã2ã€ã®ã¬ãã¥ãŒãµãŒã§æ§æãããŠããå Žåãæ¬¡ã®æ§é ãåŸãããŸãã
employees {state: COMPLETE, data: [{id: 1, ...}, {id: 2, ...}]} selectedEmployees Map({1 => true})
3çªç®ã®æ¹æ³ïŒ
æéãçµã€ã«ã€ããŠãæ¯å2çªç®ã®ã¡ãœããã䜿çšãããšãåŸæ¥å¡ãselectedEmployeesãåŸæ¥å¡ãemployeeTestãªã©ã§æ§æãããè¥å€§åããç¶æ
ã«ãªããŸãããªãã¥ãŒãµãŒã¯çžäºã«é¢é£ããŠããããšã«æ³šæããŠãã ããïŒselectedEmployeesã¯åŸæ¥å¡ãæããemployeeTestã¯åŸæ¥å¡ãæããŸãã ãããã£ãŠãè€åæžéæ©ãäœæããŠã¢ããªã±ãŒã·ã§ã³ãæ§æããŸãã ããã«ãããããæç¢ºã§äŸ¿å©ãªæ§é ãåŸãããŸãã
employees: - list [{id: 1, ...}, {id: 2, ...}] - selected Map({1 => true}) - status COMPLETE employee: - data - test
ãã®ãããªæ§é ã¯ãã¬ãã¥ãŒãµãŒã®éå±€ãæ§ç¯ããããšã§å®çŸã§ããŸãã
export const createReducer = () => { return combineReducers({ employees: combineReducers({ list: employees, selected: selectedEmployees, status: employeesStatus }) routing: routeReducer, }); };
泚ïŒãã®ã¬ãã«ã§ã¯ã¹ããŒã¿ã¹ã¯éèŠã§ã¯ãããŸããã以åã®ããã«ãåŸæ¥å¡ã®ãªã¹ããæ
åœãããªãã¥ãŒãµãŒå
ã«æ®ãããšãã§ããŸãããããã䜿çšããããšã«ããæ¹æ³ã§ãã ãªããžã§ã¯ãã®ã°ã«ãŒãäœæ¥ãå¿
èŠãªããŸããŸãªç¶æ³ã«æé©ã§ãã
ç¶æ³2ïŒãããŒã¿ã®æ£èŠåã
SPAã®éçºã§ã¯ãããŒã¿ã®æ£èŠåã倧ããªåœ¹å²ãæãããŸãã ä»åŸãåŸæ¥å¡ãšååããŠãããŸãã é©åãªåŸæ¥å¡ãéžæãããã¹ãã«éããŸããã ãã®åŸãåŸæ¥å¡ã¯åæ ŒããäŒç€Ÿã¯ãã¹ãçµæãåãåããŸãã ã¢ããªã±ãŒã·ã§ã³ã«ã¯ããŒã¿ãä¿åããå¿
èŠããããŸã-åŸæ¥å¡ã®ãã¹ãçµæã 1人ã®åŸæ¥å¡ãè€æ°ã®çµæãæã€å ŽåããããŸãã
åæ§ã®åé¡ã¯ãããã€ãã®æ¹æ³ã§ã解決ã§ããŸãã
æªãéïŒç·ãã³ãïŒ
ãã®æ¹æ³ã¯ããã¹ãã«é¢ããå®å
šãªããŒã¿ãå
éšã«ä¿åãããããªæ¹æ³ã§åŸæ¥å¡æ§é ãæ¹è¯ããããšãææ¡ããŸãã ããã¯ïŒ
employees: { status: COMPLETE, list: [ { id: 1, name: '', testResults: { id: 123, score: 5 speed: 146, description: '...' ... } } ] }
ã¹ãã¢ã«ãªãŒã±ã¹ãã©ãªããžã§ã¯ããååŸããŸããã ããã¯äžäŸ¿ã§ãäœåãªãã¹ãããããŸãã æ£èŠåãããããŒã¿ã䜿çšãããœãªã¥ãŒã·ã§ã³ã¯ããã£ãšãããã«èŠããŸãã
ããæ¹æ³
åŸæ¥å¡ãšãã¹ãã«ã¯idãããããšã«æ³šæããŠãã ããã ããŒã¿ããŒã¹ã«ã¯ãåŸæ¥å¡IDã ãã§ãã¹ããšåŸæ¥å¡ã®éã«æ¥ç¶ããããŸãã ããã¯ãšã³ãããåãã¢ãããŒããåããæ¬¡ã®æ§é ãååŸããŸãã
employees: { status: COMPLETE, list: [ { id: 1, name: '', testResults: [123] } ] }, tests: { 123: { id: 123, score: 5 speed: 146, description: '...' ... } }
ã«ãŒãã¬ãã¥ãŒãµãŒã§ã¯æ¬¡ã®ããã«ãªããŸãã
export const createReducer = () => { return combineReducers({ employees: combineReducers({ list: employees, selected: selectedEmployees, status: employeesStatus }), tests, routing: routeReducer, }); };
ã¹ãã¢ãæ§ç¯ãããã¹ãŠãæ£ã«çœ®ããã¢ããªã±ãŒã·ã§ã³ã®æ©èœãæç¢ºã«çè§£ããŸããã
ã¢ãžã¥ãŒã«ã远å ãã
ã¢ãžã¥ãŒã«ã远å ãããšããç¶æ
ãã¥ãŒãå
±éã®ã°ã«ãŒããšç°ãªãã¢ãžã¥ãŒã«ã«å±ããã°ã«ãŒãã«åå²ããŸãã
export const createReducer = () => { return combineReducers({ moduleA: combineReducers({ employees: combineReducers({ list: employees, selected: selectedEmployees, status: employeesStatus }), tests, }), moduleB: combineReducers({...}),
ãã®ã¡ãœããã䜿çšãããšãã¹ãã¢ã®æ§é å
ã§ãã¡ã€ã«æ§é ãç¹°ãè¿ãããšãã§ããŸãã ãããã£ãŠãã¢ããªã±ãŒã·ã§ã³ã®æ§é ã¯ããã¡ã€ã«ã¬ãã«ãšè«çã¬ãã«ã®äž¡æ¹ã§ç¹°ãè¿ãããŸãã ããã¯ãã¢ããªã±ãŒã·ã§ã³å
šäœã®äœæ¥å
šäœã®çè§£ãç°¡çŽ åãããæ°ããéçºè
ãããââãžã§ã¯ãã«åå ããããã®ãããå€ãäœããªãããšãæå³ããŸãã
React Component Buildingã®åå
ã¢ããªã±ãŒã·ã§ã³æ§é ã®æ§ç¯ã«æåããã³ãŒããã¢ãžã¥ãŒã«ã«åå²ããŸãããã¢ã¯ã·ã§ã³ãšã¬ãã¥ãŒãµãŒã¯éå±€çã§ãããã¹ã±ãŒã©ãã«ãªã³ãŒããèšè¿°ã§ããŸãã UIãæ
åœããã³ã³ããŒãã³ããã©ã®ããã«æ§ç¯ããããšãã質åã«æ»ããŸãããã
ç§ãã¡ã¯ãªãã¥ãŒã¹ã®ååãé å®ããŸããã€ãŸããã°ããŒãã«ãªåŽé¢ãå¯äžã®çå®ã®æºã§ãã ç§ãã¡ã®ç®æšã¯ãã¹ãã¢ããã®ããŒã¿ã«å¿ããŠããã€ã§ããµã€ãã®è¡šç€ºãå®å
šã«åŸ©å
ã§ããããã«ã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããããšã§ãã 蚱容ããããšã©ãŒã®ãã¡ãã¢ãã¡ãŒã·ã§ã³/ããããããŠã³ã®ç¶æ
ãããŒã«ããã-ãªãŒãã³/ã¯ããŒãºã«é¢ããããŒã¿ã埩å
ããªãããã«ããŸãã
ãããã®æ¡ä»¶ã«åºã¥ããŠãã¢ããªã±ãŒã·ã§ã³ã¢ãã«ãæ§ç¯ããŸãã
ã¹ããŒãã³ã³ããŒãã³ããšãã ã³ã³ããŒãã³ã
以äžã®ãªãœãŒã¹ã§ãããã®ç¹æ§ãæ§ç¯ããã³åé¢ããããã®ååã«èª¬æãããã¢ãããŒãïŒ
»
Medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0#.aszvx1fh1»
Jaketrent.com/post/smart-dumb-components-reactåæ§ã®ã¢ãããŒããåããŸãã ãã¹ãŠã®å
±éã³ã³ããŒãã³ãã¯ãããããã£ãªã©ã®ã¿ãåãåããããŒã³ã³ããŒãã³ãã§ããç¹å®ã®ã¢ãžã¥ãŒã«ã«é¢é£ããã³ã³ããŒãã³ãã¯ãã¹ããŒããŸãã¯ãã ã®ããããã§ãã æ§é å
ã§ããããæç¢ºã«åºå¥ããã®ã§ã¯ãªããè¿ãã«ä¿åãããŸãã
ããããªéšå
ã»ãŒãã¹ãŠã®ã³ã³ããŒãã³ãã«ç¬èªã®ç¶æ
ã¯ãããŸããã ãã®ãããªã³ã³ããŒãã³ãã¯ãæ¥ç¶ãã³ã¬ãŒã¿ãä»ããŠããŸãã¯äžäœã³ã³ããŒãã³ãããã®ããŠã©ãŒã¿ãŒãã©ãŒã«ãã®å©ããåããŠãç¶æ
ãã¢ã¯ã·ã§ã³äœæè
ãåãåããŸãã
ããããç¬èªã®ç¶æ
ãæã€ã³ã³ããŒãã³ãã®çŽ5ïŒ
ããããŸãã ãããã®ã³ã³ããŒãã³ãã¯äœã§ããïŒ åœŒãã®ã¢ãŒãã«ã¯äœãä¿åãããŠããŸããïŒ ãã®ã¢ããªã±ãŒã·ã§ã³ã®åæ§ã®ã³ã³ããŒãã³ãã¯ã2ã€ã®ã°ã«ãŒãã«åããããšãã§ããŸãã
ãããã¢ããã¹ããŒã¿ã¹ïŒ
å¥ã®äŸïŒ
ãã®ã°ã«ãŒãã«ã¯ãæ
å ±ãä¿åããã³ã³ããŒãã³ããå«ãŸããŸã-ãããã¢ããèŠçŽ ïŒããããããŠã³ãããŒã«ãããïŒã衚瀺ãããã©ããã
ãã®ãããªã³ã³ããŒãã³ãã®å
žåçãªã³ãŒãïŒ
import React, { Component } from 'react'; import PseudoLink from '../pseudoLink/pseudoLink'; import Dropdown from '../../common/dropdown/dropdown'; import './dropdownHint-styles.less'; class DropdownHint extends Component { constructor(props, context) { super(props, context); this.state = { dropdown: false, }; } renderDropdown() { if (!this.state.dropdown) { return ''; } return ( <Dropdown onClose={() => { this.setState({ dropdown: false, }); }}> <div className='dropdown-hint'>{this.props.children}</div> </Dropdown> ); } render() { return ( <PseudoLink onClick={() => { this.setState({ dropdown: true, }); }}> {this.renderDropdown()} {this.props.text} </PseudoLink> ); } } export default DropdownHint;
å
éšç¶æ
ã®2çªç®ã®ã¿ã¹ã¯ïŒäžæçãªãã£ãã·ã¥ãŸãã¯è¿œå ã
次ã®äŸãèããŠã¿ãŸãããã
ç»é¢äžéšã®éç¥ã¯ã衚瀺ãŸãã¯é衚瀺ã«ãªããšã¢ãã¡ãŒã·ã§ã³åãããŸãã éç¥ã®æ¬è³ªã¯ã°ããŒãã«ã¢ããªã±ãŒã·ã§ã³ç¶æ
ã«ä¿åãããŸãããéç¥ãé衚瀺ã«ããïŒãã®åŸã®åé€ã䌎ãïŒããã»ã¹ã§ã¯ãã¢ãã¡ãŒã·ã§ã³ãªã©ã®éèŠã§ãªãæ
å ±ã§ã°ããŒãã«ç¶æ
ãæ±æããããšãªããããã€ãã®ã¢ãããŒãã®ããããã䜿çšã§ããŸãã
æåã®æ¹æ³ã¯ãã£ãã·ã¥ã§ããããªãç°¡åãªæ¹æ³ã NotificationsManagerã³ã³ããŒãã³ããäœæããŸããããã¯ãNotificationã³ã³ããŒãã³ãã®ã¬ã³ããªã³ã°ãæ
åœããŸãã NotificationsManagerãæ¬¡ã®éç¥ãã¬ã³ããªã³ã°ããåŸãã¿ã€ããŒãéå§ãããã®åŸãéç¥ãé衚瀺ã«ããã¢ã¯ã·ã§ã³ãåŒã³åºãããŸãã åŒã³åºãåã«ãNotificationsManagerã¯éç¥ããã£ãã·ã¥ããŸãã ããã«ãããéç¥èªäœãã¹ãã¢ããåé€ã§ããŸãããŸããã³ã³ããŒãã³ãã®ããŒã«ã«ç¶æ
å
ã®ãã£ãã·ã¥ãããããŒã¿ã«ãããæ¶å€±ãã¢ãã¡ãŒã·ã§ã³åã§ããŸãã
ãã®æ¹æ³ã¯ãç§ãã¡ã®åŽã欺ããšããç¹ã§äžäŸ¿ã§ã-圌ã¯éç¥ããªããšä¿¡ããŠããŸãããå®éã«ã¯ã³ã³ããŒãã³ãã®ããŒã«ã«ããŒãžã§ã³ã«ä¿åãããŠããŸãã ãèª å®ãªãããŒãã£ãå¿
èŠãªã®ã§ããã®æ¹æ³ã¯ç§ãã¡ã«ã¯é©ããŠããŸããã
2çªç®ã®æ¹æ³-ã¹ãã¢ããã®æ
å ±ãããŒã«ã«ã«è£å®ããŸãããã®æ¹æ³ã¯ãã¹ãã¢ããããŒã¿ã埩å
ããããã®é«ç²ŸåºŠã劚ããªããããããæ£çŽã§é
åçã§ãã NotificationsManagerã¯ãã¹ãã¢ã®åŽããéç¥ãžã®å€æŽãåãåããšãéç¥ã§å®è¡ããå¿
èŠã®ããæ
å ±ïŒå€èгã®è¡šç€ºãæ¶å€±ããŸãã¯äœãããªãïŒã«é¢ããæ
å ±ããã®ç¶æ
ã«è¿œå ãããšããäºå®ããæããŸãã ãã®å ŽåãNotificationManagerã¯ãéç¥ã®æ¶å€±ã®ã¢ãã¡ãŒã·ã§ã³ãå®äºããå Žåã«ã®ã¿ãCLOSE_NOTIFICATIONã¢ã¯ã·ã§ã³ãä»ããŠããŒãã£ã«éç¥ããŸãã ãã®ã¢ãããŒãã«ãããã¹ãã¢å
ã®äžå¿
èŠãªæ
å ±ïŒéç¥ã¢ãã¡ãŒã·ã§ã³ã¹ããŒã¿ã¹ïŒãç Žæ£ããããšãã§ããåæã«ã¹ãã¢ã¯ãå¯äžã®çå®ã®æºãã§ãããã¢ããªã±ãŒã·ã§ã³å
šäœã®è¡šç€ºãæ£ç¢ºã«åŸ©å
ã§ããŸãã
ãã®ã¢ãããŒããã©ã®ããã«æ©èœãããããããã説æããŸãã ã¹ãã¢ã§ã¯æ¬¡ã®ãã®ãååŸããŸãã
notifications: [ { id: 1, text: ' , ' }, { id: 2, text: ' , ' }, { id: 3, text: ' , ?' }, ]
ããŒã«ã«ã³ã³ããŒãã³ãã®ã¹ã¿ã€ã«ïŒ
notifications: { 1: 'out', 3: 'in' }
äŸãèŠãŠã¿ãŸãããã ã¢ããªã±ãŒã·ã§ã³å
šäœã®ã¬ãã«ã§ã¯ã3ã€ã®éç¥ãããããšãããããŸãã ã³ã³ããŒãã³ãã®ããŒã«ã«ã¬ãã«ã§ã¯ãã¢ããªã±ãŒã·ã§ã³ã«ãšã£ãŠæå³ãæããªãæ
å ±ãä¿åããŸãããããŒã«ã«ã¬ã³ããªã³ã°ã«ã¯éèŠã§ããid=== 1ãæ¶ããid == 3ãæ®ããid === 2ã¯éçã§ãã
, . , . . â- â.
. , , , . . , . .
.
. react-router, redux react-router-redux.
.
, json, : , , ( ). .
:
- js ;
- , ;
- node.js .
json-. acceptType-.
:
employees (employees) (account).
, html-, json:
window.pageData = { account:
, , .
:
const initialData = window.pageData.employees; export default function employees(state = initialData, actions) {
employees , -, .
â . action creator, acceptType: application/json ( ). . â â.
action creator':
export function loadEmployee(id) { return dispatch => {
receiveEmployee. , , , . . â catch :
- ;
- ;
- ;
- react .
- ââ . , , t('employee.error'). t â , ().
ââ . , , , . . , : . . , :
export function loadEmployee(id) { return async dispatch => {
try-catch dispatch:
dispatch(receiveEmployee(result));
, catch:
export function loadEmployee(id) { return async dispatch => {
, .
, , , , ., , , â â. (, 5â10 , 40â50 ) . ? , . , . , â â , . , , , -, , -, (, , ). , , . . , .
:
»
github.com/reactjs/redux/issues/37#issue-85098222»
gist.github.com/gaearon/0a2213881b5d53973514»
stackoverflow.com/questions/34095804/replacereducer-causing-unexpected-key-error:
ã¹ããã1, . , . ( ).
ã¹ããã2. :
export const createReducer = () => { return combineReducers({ moduleA: combineReducers({ employee: combineReducers({ list: employees, selected: selectedEmployees, status: employeesStatus }), tests, }), moduleB: combineReducers({...}),
:
export const createReducer = (dynamicReducers = {}) => { return combineReducers(Object.assign({}, { notifications, routing: routeReducer,
, :
export const aReducers = { moduleA: combineReducers({ employee: combineReducers({ list: employees, selected: selectedEmployees, status: employeesStatus }), tests, }), }
ã¹ããã3, :
export function configureStore() { const store = createStoreWithMiddleware(createReducer()); store.dynamicReducers = {}; storeInstance = store; switch (store.getState().module) { case A: injectAsyncReducer(aReducers); break case B: injectAsyncReducer(bReducers); break;
injectAsyncReducer, .
ã¹ããã4action creator. action . :
export const checkoutAModule = () => {
, , .
ã¹ããã5, . :
import React, { Component } from 'react'; import { connect } from 'react-redux'; import { checkoutModuleA } from '../../actions/module'; import { A } from '../../constants/module'; export default function checkoutA() { return Container => { class AContainer extends Component { componentWillMount() { if (this.props.module !== A) { this.props.checkoutModuleA(); } } render() { return ( <Container {...this.props} /> ); } } return connect( state => { return { module: state.module, }; }, { checkoutModuleA, } )(AContainer); }; }
, , .
6.:
import React, { Component } from 'react'; import { connect } from 'react-redux'; import { compose } from 'redux'; import Content from '../components/content/content'; import Managers from '../components/managers/managers'; import composeRestricted from './restricted/restricted'; import { loadManagers } from '../actions/managers'; import title from './title/title'; class ManagersPage extends Component { componentWillMount() { if (!this.props.firstLoad) { this.props.loadManagers(this.props.location); } } render() { return ( <div className='page'> <Content> <Managers /> </Content> </div> ); } } export default compose( connect( state => state.location, {loadManagers} ), checkoutA(), title('managers', 'title.base'), composeRestricted({user: true}) )(ManagersPage);
ã§ããïŒ .
, . , ââ . (, , ).
. , . , , , , . , ( ), .