Microsoft To-Do
React practices
π my name is Alex
Microsoft To-Do
React
Redux
Redux-actions
ES6 + TypeScript
eslint plugins
ImmutableJS
...
Just a To-Do list...
Reselect
Design Principles
Data-Driven Design
Immutable Design
Composable abstractions
Domain-Driven Design
Maintenance and Change
Explicitness
Passing state
vs.
ICC
ICC
=
Independently
Connected
Components
We connect
every tiny single component
to the store
The art and magic
of state passing
State Passing
Model Passing
Primitives Passing
props.completed
props.todo.completed
Model Passing
- Data hierarchy == View hierarchy
- Expensive updates
- Very sensitive to changes
- Where do I add child data?
- Derived data dependencies
Easy vs. Performant
Primitives Passing
- Data hierarchy == View hierarchy
Expensive updates- Sensitive to changes
- Where do I add child data?
Derived data dependencies- Does not extend (too many things)
Performant vs. Extensible
ICC
Data hierarchy == View hierarchyExpensive updatesSensitive to changesWhere do I add child data?Derived data dependenciesDoes not extend (too many things)- Performance?
- SCARY!!!
Extensible vs. ?
Let's split!
Data vs View
Connector + Component = single entity
ICC Data Hierarchy
Not so scary...
ICC View Hierarchy
Not so scary...
Performance
As if no one asks about performance...
Worry not!
State passing
ICC
Now FIGHT!!!
Huge list = 500 tasks
~20 Drag'n'Drop wrappers
1 ICC Task =Β
~7 Components
~50 properties
~25 handlers
1 prim. Task =Β
Some context
Β Nested Connectors
~1700 ms π±
ICC + react-redux < v5.0.0
~600 ms πͺ
No Batcher + react-redux < v5.0.0
No Batcher + react-redux v5.0.0beta3
~500 ms π
Primitives + react-redux v5.0.0beta3
~450 ms π
More components = less overhead
What we have learned?
25 items -> ~50ms,
500 items -> ~300ms
Our DnD implementation
=
Β 50% perf overhead
What we have learned?
Every connect()
adds
~0.1ms to initial rendering time
What we have learned?
State Passing isΒ ~10% faster in our hot rendering path π₯but ...
Single file with ~50 selectors and 25 handlers π
What we have learned?
Complexity
vs.
a bit of Performance
What we have learned?
Measure in your own case π
Use virtualized lists π
Do not create custom Batchers π©
Compose behaviours with React components mindfully
How toΒ ICC
ICC in the wild
1. Connect is partially applied
2. Index exports (component + connect)
3. Specialization goes to subdirectories
ICC in the wild - connect
import { connect } from 'react-redux'
import ...
const mapStateToProps = createSelector(
getAddTask,
...,
(addTask, ...) => ({
title: addTask.title,
...
})
)
const mapActionsToProps = dispatch => ({
onChange: ({ title }) => dispatch(updateAddTask({ title })),
...
})
export default connect(mapStateToProps, mapActionsToProps)
ICC in the wild - Component
import React, { PropTypes } from 'react'
...
export default class AddTask extends React.Component {
// ...
render() {
const { title, onFocus, onPlusClick, isFocused } = this.props
const placeholder = LocalizedString.getString('placeholder_add_task')
return (
<div className="addTask">
<button
className="addTask-icon"
onClick={ onPlusClick }
>
<Icon name={ iconName }/>
</button>
// ...
</div>
)
}
}
ICC in the wild - default/index
import React from 'react'
import AddTask from '../AddTask'
import connect from '../connect'
import '../addTask.styl'
export default connect(AddTask)
Using ICC
import AddTask from 'components/AddTask'
// Component stuff ...
render() {
return (
<AddTask intentOrigin={ intentOrigin } />
)
}
Another Example
import React, { PropTypes } from 'react'
import TaskItem from '../TaskItem'
import connect from './connect'
import Checkbox from 'components/Checkbox'
const DefaultTaskItem = props =>
<TaskItem
primaryActionComponent={ <Checkbox id={ props.id } intentOrigin={ props.intentOrigin }/> }
{ ...props }
/>
DefaultTaskItem.propTypes = {
id: PropTypes.string.isRequired,
inToday: PropTypes.bool,
intentOrigin: PropTypes.string
}
export default connect(DefaultTaskItem)
ComposableΒ StoreΒ
Normalized State
Directory structure
===
state structure
State is composed of domains
1. No derived data in domains
2. Single Source of Writes
3. Represents Domain Entities
4. Indexed (byId, byOrder)
Example of a domain
1. Derived Data is in selectors
Crucial Conventions
2. Action is handled by only one reducer
3. Actions have domain-specific names
4. Dependent actions
What's next?
Relationships
Transactions
More structure
State machines?
Going deeper...
Basics
π First Normal Form
π Data Domain
Advanced
π CQRS Explained
Black Magic
π Statecharts
Thank you!
Questions?
How Microsoft To-Do uses React
By Alexey Migutsky
How Microsoft To-Do uses React
- 3,915