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的更多相关文章

  1. [Redux] Extracting Container Components (FilterLink)

    Learn how to avoid the boilerplate of passing the props down the intermediate components by introduc ...

  2. [Redux] Extracting Container Components -- VisibleTodoList

    Code to be refacted: const TodoList = ({ todos, onTodoClick }) => ( <ul> {todos.map(todo =& ...

  3. [Redux] Redux: Extracting Container Components -- AddTodo

    Code to be refactored: const AddTodo = ({ onAddClick }) => { let input; return ( <div> < ...

  4. [Redux] Extracting Presentational Components -- AddTodo

    The code to be refactored: let nextTodoId = 0; class TodoApp extends Component { render() { const { ...

  5. [Redux] Extracting Presentational Components -- Footer, FilterLink

    Code to be refactored: let nextTodoId = 0; class TodoApp extends Component { render() { const { todo ...

  6. [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 ...

  7. [Redux] Extracting Presentational Components -- Todo, TodoList

    Code to be refactored: let nextTodoId = 0; class TodoApp extends Component { render() { const { todo ...

  8. Presentational and Container Components

    https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0 There’s a simple pattern I fi ...

  9. (翻译)React Container Components

    原文:Container Components Container Components 在 React 模式上对我的代码有最深远影响的一个模式叫 container component 模式. 在 ...

随机推荐

  1. 如何解决svn图标不显示呢?

    svn图标不显示解决 确保设置正确: 右键->TortoiseSVN->setting->Icon Overlays->Status cache->default/She ...

  2. ls 命令详解

    1.ls基本语法及选项 用法:ls [选项]... [文件]... List information about the FILEs (the current directory by default ...

  3. 初探R语言——R语言笔记

    R语言使用 <-  赋值 # 作为注释符号 c()函数用于作为向量赋值,例如age<-c(1,2,3,4,5) mean()用于求向量的平均值 sd()求向量的标准差 cor(a,b)求a ...

  4. InstallShield常用prq文件的下载地址

    VC 2010 redist X86: http://saturn.installshield.com/is/prerequisites/microsoft visual c++ 2010 redis ...

  5. traceroute小结 come from CSDN author:houdong

    traceroute程序可以使我们看到IP数据报从一台主机传到另一台主机的所经过的路由,并且可以使用IP源站路由选项. traceroute取代IP RR的原因 1 不是所有的路由器都支持IP RR选 ...

  6. ROBOTS.TXT屏蔽笔记、代码、示例大全

    自己网站的ROBOTS.TXT屏蔽的记录,以及一些代码和示例: 屏蔽后台目录,为了安全,做双层管理后台目录/a/xxxx/,蜘蛛屏蔽/a/,既不透露后台路径,也屏蔽蜘蛛爬后台目录 缓存,阻止蜘蛛爬静态 ...

  7. 用lambda表达式替代 for循环进行批量操作。

    IEnumerable<Rect> rectlist3 = rectlist.Select(rect =>newRect(rect.X + 2000, rect.Y, rect.re ...

  8. fiddler使用之坑

    今天一上午都在搞fiddler,之前可以抓到浏览器的请求,今天突然不行了,弄得我花一上午时间去设置浏览器代理的事情,遇到各种各样的问题,现将解决办法记录如下: 1.原来fiddler安装在E盘中,安装 ...

  9. 十六进制string转换UIColor -备用

    - (UIColor *) colorWithHexString: (NSString *) stringToConvert { NSString *cString = [[stringToConve ...

  10. 『安全工具』目录扫描 DirBuster AND 御剑

    要想熟悉目标网站的体系架构,知道网站有哪些目录是必不可少的 向AWVS,Burp类大型扫描工具也可以进行目录扫描,不过个人感觉远没有专业扫描工具来的简单,实在 0x 01 DirBuster 简介:D ...