Scaling React.js ApplicationsMax Stoiber, @mxstbrOpen Source Developer, Thinkmill
View Slide
@mxstbr
KeystoneJS
ElementalUI
@mxstbr2. State Management3. Architecture1. What is Scalability?4. Performance
@mxstbrUnidirectional Data Flow
@mxstbrStore
@mxstbrContainers and Components
@mxstbrStructure
@mxstbrTraditionally grouped by type
@mxstbrreact-app-by-type!"" css!"" actions# $"" NavBarActions.js!"" containers# $"" NavBar.js!"" constants# $"" NavBarConstants.js!"" components# $"" App.js$"" reducers$"" NavBarReducer.js
@mxstbrGroup by feature instead
@mxstbrreact-app-by-feature!"" css!"" containers# $"" NavBar# !"" NavBar.js# !"" actions.js# !"" constants.js# $"" reducer.js$"" components$"" App.js
@mxstbrEasy renaming and moving
@mxstbrimport { toggleNav } from ‘containers/NavBar/actions.js’;
@mxstbrimport { toggleNav } from ‘containers/PrimaryNav/actions.js’;
@mxstbrWork in a single folder
@mxstbrReusable components
@mxstbrStyling??
@mxstbr.header {/* … */}.title {background-color: yellow;}.footer {/* … */}.title {border-color: blue;}Conflict!Naming
@mxstbrCSS Modules
@mxstbrimport styles from ‘styles.css’;render() {return (className={styles.footer}/>);}
@mxstbr.footer { /* … */ }.title { /* … */ }.MyApp__footer__1co1k { /* … */ }.MyApp__title__2fgr5s { /* … */ }
@mxstbr.header { line-height: 1.5em; }a { line-height: 1.5em; }.title { line-height: 1.5em; }Inheritance
@mxstbr.header {line-height: 1.5em;}.title {line-height: 1.5em;}Inheritance.footer {line-height: 1em;}.title {line-height: 1em;}Conflict!
@mxstbrResetHeaderTitleGlobal ResetResetHeaderLocal ResetResetTitle
@mxstbrPostCSS
@mxstbrPostCSS+postcss-autoreset
@mxstbr.header { line-height: 1.5em; }a { line-height: default; }.title { line-height: default; }
@mxstbrreact-app-by-feature!"" containers# $"" NavBar# !"" NavBar.js# !"" actions.js# !"" constants.js# !"" styles.css# $"" reducer.js$"" components$"" App.js
@mxstbrComponent Isolation!
@mxstbrData Fetching??
@mxstbronStartClick={dipatch(startTimer())}/>onStopClick={dispatch(showTime())}/>
@mxstbrredux-saga
@mxstbronStartClick={dipatch(startClicked())}/>onStopClick={dispatch(stopClicked())}/>
@mxstbrfunction* connectClockToTimer() {while (true) {yield take(START_BUTTON_CLICKED);put(startTimer());yield take(STOP_BUTTON_CLICKED);put(stopTimer());put(showTimeOnClock());}}
@mxstbrDecoupled Components
@mxstbr2. Group files by feature3. Isolate Styling1. Containers and Components4. Use redux-saga
@mxstbrWebpackCode Splitting
@mxstbrshouldComponentUpdate
@mxstbrclass NavBar extends React.Component {shouldComponentUpdate(nextProps) {?????}}
@mxstbrclass NavBar extends React.Component {shouldComponentUpdate(nextProps) {return nextProps !== this.props;}}
@mxstbr{ “username”: “@mxstbr” } { “username”: “@mxstbr” }!==
@mxstbrDeeply comparing objectsis expensive
@mxstbrImmutableJS
@mxstbrimport { fromJS } from ‘immutable’;const state = fromJS({“username”: “@mxstbr”});
@mxstbr.equalsfromJS({ “username”: “@mxstbr” })fromJS({ “username”: “@mxstbr” })
@mxstbrDeeply comparing objectsis cheap!
Thanks for having me!Tweet comments/feedback to @mxstbrCome talk to me!