vs.
=
Independently
Connected
Components
props.completed
props.todo.completed
Model Passing
Easy vs. Performant
Primitives Passing
Performant vs. Extensible
ICC
Extensible vs. ?
Not so scary...
Not so scary...
Rendering: 1717 ms
Total: 1680 ms
ICC + react-redux < v5.0.0
Rendering: 600 ms
Total: 1660 ms
No Batcher + react-redux < v5.0.0
Rendering: 500 ms
Total: 1720 ms
No Batcher + react-redux v5.0.0beta3
Composing behaviour using React components may not be the best idea...
...but that's a different story!
More components = less overhead
25 items -> ~50ms, 500 items -> ~300ms
Every connect() adds 0.1ms to initial rendering time
State Passing is <10% faster in our hot rendering path 🔥but ...
Single file with ~50 selectors and 25 handlers 🙀
Complexity
vs.
a bit of Performance
1. Connect is partially applied
2. Index exports (component + connect)
3. Specialization goes to subdirectories
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)
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>
)
}
}
import React from 'react'
import AddTask from '../AddTask'
import connect from '../connect'
import '../addTask.styl'
export default connect(AddTask)
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)
import AddTask from 'components/AddTask'
// Component stuff ...
render() {
return (
<AddTask intentOrigin={ intentOrigin } />
)
}
Directory structure
===
state structure
1. No derived data in domains
2. Single Source of Writes
3. Represents Domain Entities
4. Indexed (byId, byOrder)
1. Derived Data is in selectors
2. Action is handled by only one reducer
3. Actions have domain-specific names
4. Dependent actions