[Redux] Extracting Container Components -- Complete
Clean TodoApp Component, it doesn't need to receive any props from the top level component:
const TodoApp = () => (
<div>
<AddTodo />
<VisibleTodoList />
<Footer />
</div>
);
Also we don't need wrap ReactDOM.render() into a render function and subscribe it, because the container component will update itself when state changes:
// From
const render = () => {
ReactDOM.render(
<TodoApp
{...store.getState()}
/>,
document.getElementById('root')
);
}; store.subscribe(render);
render(); // To
ReactDOM.render(
<TodoApp
{...store.getState()}
/>,
document.getElementById('root')
);
The first component I'm looking at is called AddToDo. Frankly, I cant classify it either as a presentational component or as a container component because it doesn't fit either category. The input and the button are the presentational part, but dispatching an action onClick is the behavior which is usually specified by the container.
However, in this case, I'd rather keep them together because there isn't any state, the UI is very simple. It's hard to imagine any other behavior other than dispatching the AddToDo action.
-----
In general, I suggest first trying to extract the presentational components. If there is too much boilerplate passing the props through them, then you can create the containers around them that load the data and specify the behavior.
--------------
Code:
const todo = (state, action) => {
switch (action.type) {
case 'ADD_TODO':
return {
id: action.id,
text: action.text,
completed: false
};
case 'TOGGLE_TODO':
if (state.id !== action.id) {
return state;
}
return {
...state,
completed: !state.completed
};
default:
return state;
}
};
const todos = (state = [], action) => {
switch (action.type) {
case 'ADD_TODO':
return [
...state,
todo(undefined, action)
];
case 'TOGGLE_TODO':
return state.map(t =>
todo(t, action)
);
default:
return state;
}
};
const visibilityFilter = (
state = 'SHOW_ALL',
action
) => {
switch (action.type) {
case 'SET_VISIBILITY_FILTER':
return action.filter;
default:
return state;
}
};
const { combineReducers } = Redux;
const todoApp = combineReducers({
todos,
visibilityFilter
});
const { createStore } = Redux;
const store = createStore(todoApp);
const { Component } = React;
const Link = ({
active,
children,
onClick
}) => {
if (active) {
return <span>{children}</span>;
}
return (
<a href='#'
onClick={e => {
e.preventDefault();
onClick();
}}
>
{children}
</a>
);
};
class FilterLink extends Component {
componentDidMount() {
this.unsubscribe = store.subscribe(() =>
this.forceUpdate()
);
}
componentWillUnmount() {
this.unsubscribe();
}
render() {
const props = this.props;
const state = store.getState();
return (
<Link
active={
props.filter ===
state.visibilityFilter
}
onClick={() =>
store.dispatch({
type: 'SET_VISIBILITY_FILTER',
filter: props.filter
})
}
>
{props.children}
</Link>
);
}
}
const Footer = () => (
<p>
Show:
{' '}
<FilterLink
filter='SHOW_ALL'
>
All
</FilterLink>
{', '}
<FilterLink
filter='SHOW_ACTIVE'
>
Active
</FilterLink>
{', '}
<FilterLink
filter='SHOW_COMPLETED'
>
Completed
</FilterLink>
</p>
);
const Todo = ({
onClick,
completed,
text
}) => (
<li
onClick={onClick}
style={{
textDecoration:
completed ?
'line-through' :
'none'
}}
>
{text}
</li>
);
const TodoList = ({
todos,
onTodoClick
}) => (
<ul>
{todos.map(todo =>
<Todo
key={todo.id}
{...todo}
onClick={() => onTodoClick(todo.id)}
/>
)}
</ul>
);
const AddTodo = ({
onAddClick
}) => {
let input;
return (
<div>
<input ref={node => {
input = node;
}} />
<button onClick={() => {
store.dispatch({
type: 'ADD_TODO',
id: nextTodoId++,
text: input.value
});
input.value = '';
}}>
Add Todo
</button>
</div>
);
};
const getVisibleTodos = (
todos,
filter
) => {
switch (filter) {
case 'SHOW_ALL':
return todos;
case 'SHOW_COMPLETED':
return todos.filter(
t => t.completed
);
case 'SHOW_ACTIVE':
return todos.filter(
t => !t.completed
);
}
}
class VisibleTodoList extends Component {
componentDidMount() {
this.unsubscribe = store.subscribe(() =>
this.forceUpdate()
);
}
componentWillUnmount() {
this.unsubscribe();
}
render() {
const props = this.props;
const state = store.getState();
return (
<TodoList
todos={
getVisibleTodos(
state.todos,
state.visibilityFilter
)
}
onTodoClick={id =>
store.dispatch({
type: 'TOGGLE_TODO',
id
})
}
/>
);
}
}
let nextTodoId = 0;
const TodoApp = () => (
<div>
<AddTodo />
<VisibleTodoList />
<Footer />
</div>
);
ReactDOM.render(
<TodoApp
{...store.getState()}
/>,
document.getElementById('root')
);
[Redux] Extracting Container Components -- Complete的更多相关文章
- [Redux] Extracting Container Components (FilterLink)
Learn how to avoid the boilerplate of passing the props down the intermediate components by introduc ...
- [Redux] Extracting Container Components -- VisibleTodoList
Code to be refacted: const TodoList = ({ todos, onTodoClick }) => ( <ul> {todos.map(todo =& ...
- [Redux] Redux: Extracting Container Components -- AddTodo
Code to be refactored: const AddTodo = ({ onAddClick }) => { let input; return ( <div> < ...
- [Redux] Extracting Presentational Components -- AddTodo
The code to be refactored: let nextTodoId = 0; class TodoApp extends Component { render() { const { ...
- [Redux] Extracting Presentational Components -- Footer, FilterLink
Code to be refactored: let nextTodoId = 0; class TodoApp extends Component { render() { const { todo ...
- [Redux] Extracting Presentational Components -- TodoApp
Finally, I just noticed that the to-do app component doesn't actually have to be a class. I can turn ...
- [Redux] Extracting Presentational Components -- Todo, TodoList
Code to be refactored: let nextTodoId = 0; class TodoApp extends Component { render() { const { todo ...
- Presentational and Container Components
https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0 There’s a simple pattern I fi ...
- (翻译)React Container Components
原文:Container Components Container Components 在 React 模式上对我的代码有最深远影响的一个模式叫 container component 模式. 在 ...
随机推荐
- 关于material和sharedMaterial的问题
在unity3d中,Renderer组件有两个属性:material和sharedMaterial,它们都可以用来获取Renderer的材质属性.但是它们之间却又很大的区别,下面通过示例来讲解一下. ...
- Python的学习
1.psutil的安装 [root@YQY-TIAN- ~]# wget https://pypi.python.org/packages/source/p/psutil/psutil-2.0.0.t ...
- 小学生之KTV播放原理
第一步: 创建一个Song类 //歌曲名称 public string SongName { get; set; } //歌曲路劲 public string SongPath { get; set ...
- 初学Java ssh之Spring 第二篇
上一篇我们成功搭建好了spring开发的环境,接下来一起看看spring有什么神奇的地方吧(本人也是新手,有不太对的地方希望大神给指出便于修改呢,谢谢大家). 之前听说spring是在对xml文件的应 ...
- C#高级知识点概要(3) - 特性、自动属性、对象集合初始化器、扩展方法、Lambda表达式和Linq查询
1.特性(Attributes) 特性(Attributes),MSDN的定义是:公共语言运行时允许你添加类似关键字的描述声明,叫做attributes, 它对程序中的元素进行标注,如类型.字段.方法 ...
- poj1981 Circle and Points 单位圆覆盖问题
转载请注明出处: http://www.cnblogs.com/fraud/ ——by fraud Circle and Points Time Limit: 5000MS Me ...
- boost
参考博客 http://www.cnblogs.com/lidabo/p/3805487.html http://www.cppblog.com/Robertxiao/archive/2013/01/ ...
- Crontab 计划任务
有一部分工作,需要某个时间开始,每天执行,每间断一段时间执行.这个时候就需要了crontab.crontab 管理着linux上一些定期的任务.log rotate,logwatch 等等废话不多说来 ...
- php 之 数据访问 增删改查练习题
练习题内容: 一.查看新闻页面-----主页面: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ...
- table-cell的手机应用场景
前言 最近在前端观察看见了这篇老文章,看见了元素居中的5种办法,其中提到了display:table-cell这个css显示的新属性,按照当时的浏览器市场来说想必兼容性会是糟糕的一比,但是现在这坛老酒 ...