Containers
Containers are our Presenter Model (see introduction to this chapter).
They hold our business logic and compose components to display the view.
In our application the view is simple.
--------------------------
| TodoForm |
--------------------------
| TodoList |
| - TodoItem |
| - TodoItem |
| - TodoItem |
| ... |
| |
| |
| |
| |
--------------------------
TodoApp.jsx
import React, { Component, PropTypes } from 'react';
import { View } from 'react-native';
import TodoForm from '../components/TodoForm';
import TodoList from '../components/TodoList';
import TodoItem from '../components/TodoItem';
import { todoStore } from '../stores';
import styles from '../styles';
export default class TodoApp extends Component {
constructor(props) {
super(props);
this.state = todoStore.getState();
}
// Business logic methods
_onChange = (value) => {
this.setState(value);
}
addTodo(text){
todoStore.add(text);
}
onTodoClick(id) {
todoStore.complete(parseInt(id));
}
onRemoveClick(id) {
todoStore.remove(parseInt(id));
}
// React method
componentDidMount() {
todoStore.load();
todoStore.changed.add(this._onChange);
}
componentWillUnmount() {
todoStore.changed.remove(this._onChange);
}
render() {
return (
<View style={styles.container}>
<TodoForm
style={styles.form}
onAddTodo={this.addTodo} />
<TodoList
todoRenderer={TodoItem}
todoStyle={styles.todoItem}
todoCompletedStyle={styles.todoItemCompleted}
todos={this.state.todos}
onTodoClick={this.onTodoClick}
onRemoveClick={this.onRemoveClick} />
</View>
);
}
}
Let's decompose this container.
Import view components and compose the view
The container compose a view with View Components we created before (TodoItem, TodoList, and TodoForm).
This action is performed in therender()
method of a React component.<View style={styles.container}> <TodoForm style={styles.form} /> <TodoList todoRenderer={TodoItem} todoStyle={styles.todoItem} todoCompletedStyle={styles.todoItemCompleted} /> </View>
Add data to the presenter model
Data in our application leave in a Store. In order to import data in our presenter model we just import the store in the container.import todoStore from '../stores/todoStore';
In React container can stock their data in the state of the React Component. Then those data are passed to the view using props.
Link store state with container state
This step occur in theconstructor
of the container. We give the store state as initial state of the container.this.state = todoStore.getState();
Wired state and View Component props
It's time now to link store data that is on the state with our view components to display them. We see in step 1 that view composition is done in therender()
function. Data are passed to the view using props.<View style={styles.container}> <TodoForm style={styles.form} /> <TodoList todoRenderer={TodoItem} todoStyle={styles.todoItem} todoCompletedStyle={styles.todoItemCompleted} todos={this.state.todos}/> </View>
we add the list of todos contains in our container
state
in the TodoList usingtodos
props.Listen for data changes
React component livecycle provide functions to know when respecticely a component is mount and unmout. We use this to listen for storechanged
signal and update the container state._onChange(value) { this.setState(value); } componentDidMount() { todoStore.load(); todoStore.changed.add(this._onChange); } componentWillUnmount() { todoStore.changed.remove(this._onChange); }
Handling user interaction
User will interact with view components in order to add, remove, update or change todos in the list. This interaction occur on View Component but the business logic will be handle by the Container. Data are managed by the Store. The Presenter Model/Container will only dispatch signal to prevent the store to update its state.- Write business functions that dispatch store signals
addTodo(text){ todoStore.add(text); } onTodoClick(id) { todoStore.complete(parseInt(id)); } onRemoveClick(id) { todoStore.remove(parseInt(id)); }
- Link to view components
<View style={styles.container}> <TodoForm style={styles.form} onAddTodo={this.addTodo}/> <TodoList todoRenderer={TodoItem} todoStyle={styles.todoItem} todoCompletedStyle={styles.todoItemCompleted} todos={this.state.todos} onTodoClick={this.onTodoClick} onRemoveClick={this.onRemoveClick} /> </View>
Components are now display by our Container which get its data from a store. Let's add Store Commands