container/smart
Containers are application aware components. When we wrap our dumb components in a container, we give that component environment specific details to work in it's current application setting.
Containers load data in the Sideways data flow pattern.
Reusability is key, containers allow us to share a common library of stateless components, proxied for the current application. The current terminology for these components is Smart.
Containers allow a parent node to control the sub-tree's render lifecycle. A parent controlled sub-tree is any node in a react app that is responsible for rendering it's children and insulating it's children from changes in other parts of the UI.
Containers allows for fine grained control over a complex sub-tree; just ensure all data needed by children is accounted for at the container level. This is a key principal when optimizing a sub-tree.
Properties of a Container:
- No, or very minimal, props
- Insulated from changes in their parent tree
- Responsible for rendering child components when data changes
API has NO props
Keep props to a minimum and avoid when possible
<HelloWorldContainer />
Insulated from changes in their parent tree
shouldComponentUpdate() {
return false;
}
Responsible for rendering child components when data changes
componentWillMount() {
store.attachListener(this.onChange.bind(this));
}
componentWillUnount() {
store.removeListener(this.onChange.bind(this));
}
onChange() {
this.setState({
text: store.getText()
});
}
Example
Below is complete container for our HelloWorld component; the container both insulates from parent tree changes and manages connections to application stores and actions.
To build a container we pull in our application specific components and pass them as props to our stateless component. Because we subscribe to all data used by the sub-tree we can safely ignore renders triggered above us by returning false from shouldComponentUpdate
.
import store from '../stores/store';
import action from '../actions/action';
import HelloWorld from 'HelloWorld';
class HelloWorldContainer extends Component {
constructor(props) {
super(props);
this.state = {
text: store.getText(),
onChange: action.updateText,
};
}
componentWillMount() {
store.attachListener(this.onChange.bind(this));
}
componentWillUnount() {
store.removeListener(this.onChange.bind(this));
}
shouldComponentUpdate() {
return false;
}
render () {
return (
<HelloWorld {...this.state} />
);
}
onChange() {
this.setState({
text: store.getText()
});
}
}
Usage:
<HelloWorldContainer />