React practices
=
Independently
Connected
Components
props.completed
props.todo.completed
Easy vs. Performant
Performant vs. Extensible
Extensible vs. ?
(independent of parent context)
~1700 ms 😱
ICC
react-redux < v5.0.0
~600 ms 💪
No Batcher + ICC
react-redux < v5.0.0
No Batcher + ICC
react-redux v5.0.0beta3
~500 ms 👌
Single Subscribe
react-redux v5.0.0beta3
~450 ms 👍
Single Subscribe
react-redux v5.0.0beta3
~500 ms 🤔
ICC + virtualized list
react-redux v5.0.0beta3
~200 ms 👍
State Passing is ~10% faster in our hot rendering path 🔥but ...
Single file with ~50 selectors and 25 handlers 🙀
1. Connect is partially applied
2. Index exports (component + connect)
3. Specialization goes to subdirectories
import AddTask from 'components/AddTask'
// Component stuff ...
render() {
return (
<AddTask intentOrigin={ intentOrigin } />
)
}
import React from 'react'
import AddTask from '../AddTask'
import connect from '../connect'
import '../addTask.styl'
export default connect(AddTask)
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, { 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)
Directory structure
===
state structure
1. No derived data in domains
2. Single Source of Writes
3. Represents Domain Entities
4. Indexed (byId, byOrder)
Think "a table in relational DB"
1. Derived Data is in selectors
2. Action is handled by only one reducer
3. Actions have domain-specific names
4. Dependent actions
Read (domain - domain) dependencies
Write (domain->domain) relationships