Learn how to avoid the boilerplate of passing the props down the intermediate components by introducing more container components.

Code to be refactored:

const FilterLink = ({
filter,
currentFilter,
children,
onClick
}) => {
if (filter === currentFilter) {
return <span>{children}</span>;
} return (
<a href='#'
onClick={e => {
e.preventDefault();
onClick(filter);
}}
>
{children}
</a>
);
}; const Footer = ({
visibilityFilter,
onFilterClick
}) => (
<p>
Show:
{' '}
<FilterLink
filter='SHOW_ALL'
currentFilter={visibilityFilter}
onClick={onFilterClick}
>
All
</FilterLink>
{', '}
<FilterLink
filter='SHOW_ACTIVE'
currentFilter={visibilityFilter}
onClick={onFilterClick}
>
Active
</FilterLink>
{', '}
<FilterLink
filter='SHOW_COMPLETED'
currentFilter={visibilityFilter}
onClick={onFilterClick}
>
Completed
</FilterLink>
</p>
); const TodoApp = ({
todos,
visibilityFilter
}) => (
<div>
...
...
...
<Footer
visibilityFilter={visibilityFilter}
onFilterClick={filter =>
store.dispatch({
type: 'SET_VISIBILITY_FILTER',
filter
})
}
/>
</div>
);

Notice in the container component, we pass visibilityFilter to the Footer presentional component, but Footer component actually doesn't do anything about that, just pass down to the FilterLink presentional component. This is the downside for the current approach.

TodoApp (C) --> Footer (P) --> FilterLink (P)

If we met this kind of problem, what we can do is, break FilterLink into:

FilterLink (C) --> Link (P)

We convent FilterLink into a container component and make a new presentional component called 'Link'.

And inside FilterLink, we can use Redux to getState(), everytime the state change, we force the component render itself and remember to unsubscribe when the component will unmount.

Also we move the dispatch action from TodoApp container component to the FilterLink container component. So that in TodoApp, the Footer component looks nice and clean.

So now, it looks like:

TodoApp (C) --> Footer (P) --> FilterLink (C) --> Link (P)

Link (P):

const Link = ({
active,
children,
onClick
}) => {
if (active) {
return <span>{children}</span>;
} return (
<a href='#'
onClick={e => {
e.preventDefault();
onClick();
}}
>
{children}
</a>
);
};

FilterLink (C):

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>
);
}
}

Footer (P):

const Footer = () => (
<p>
Show:
{' '}
<FilterLink
filter='SHOW_ALL'
>
All
</FilterLink>
{', '}
<FilterLink
filter='SHOW_ACTIVE'
>
Active
</FilterLink>
{', '}
<FilterLink
filter='SHOW_COMPLETED'
>
Completed
</FilterLink>
</p>
);

All:

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={() => {
onAddClick(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
);
}
} let nextTodoId = 0;
const TodoApp = ({
todos,
visibilityFilter
}) => (
<div>
<AddTodo
onAddClick={text =>
store.dispatch({
type: 'ADD_TODO',
id: nextTodoId++,
text
})
}
/>
<TodoList
todos={
getVisibleTodos(
todos,
visibilityFilter
)
}
onTodoClick={id =>
store.dispatch({
type: 'TOGGLE_TODO',
id
})
}
/>
<Footer />
</div>
); const render = () => {
ReactDOM.render(
<TodoApp
{...store.getState()}
/>,
document.getElementById('root')
);
}; store.subscribe(render);
render();

[Redux] Extracting Container Components (FilterLink)的更多相关文章

  1. [Redux] Extracting Container Components -- Complete

    Clean TodoApp Component, it doesn't need to receive any props from the top level component: const To ...

  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 -- Footer, FilterLink

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

  5. [Redux] Extracting Presentational Components -- AddTodo

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

  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. Python字符串格式符号含义

    ====== #字符串格式化符号含义 #%C 格式化字符串及其ASCLL码 >>> '%c' %97 'a' >>> '%c' % 97 'a' >>& ...

  2. C# typeof Gettype is as &拆箱 装箱

    有时候,我们不想用值类型的值,就是想用一个引用..Net提供了一个名为装箱(boxing)的机制,它允许根据值类型来创建一个对象,然后使用对这个新对象的一个引用. 首先,回顾两个重要的事实,1.对于引 ...

  3. Google Guava的splitter用法

    google的guava库是个很不错的工具库,这次来学习其spliiter的用法,它是一个专门用来 分隔字符串的工具类,其中有四种用法,分别来小结 1 基本用法: String str = " ...

  4. webstrom的注释

    今天我们小组的新同学有一个BUG调不好,然后我就帮他调一下.在调试的过程中非常累,纠其原因还是他注释写的不完善.我们可以看一下,他是这样写注释的(随便拿一个方法举例),如下图: 乍一看,是不是觉得他的 ...

  5. transition Css3过度详解

    过度语法: .example { transition-property: background-color; //需要过度的css属性 transition-duration: 2s; //过度所需 ...

  6. Python 基础教程中的问题及解决方案(1)

    1. 在ubuntu中,调用终端时如: f = open('/home/theone/test_input.txt', 'r') 中的txt格式文本不能加后缀 正确的应为:  f = open('/h ...

  7. IOS NSURL基本操作-备

    NSURL其实就是我们在浏览器上看到的网站地址,这不就是一个字符串么,为什么还要在写一个NSURL呢,主要是因为网站地址的字符串都比较复杂,包括很多请求参数,这样在请求过程中需要解析出来每个部门,所以 ...

  8. gcd - b- 201611302317

    谈到iOS多线程,一般都会谈到四种方式:pthread.NSThread.GCD和NSOperation.其中,苹果推荐也是我们最经常使用的无疑是GCD.对于身为开发者的我们来说,并发一直都很棘手,如 ...

  9. 一品楼论坛www.ep6.info一品楼论坛

    一品楼论坛最新地址www.ep6.info>访问一品楼网站. 一品楼是现在比较大的信息分享平台,一品楼上网必进. 一品楼江苏版块,一品楼北京版块,一品楼怡红院,一品楼怡春院. 一品楼山东信息. ...

  10. Smartcard CA智能卡之调试

    Integrated Circuit Card  集成电路卡,也叫CA卡或智能卡,将一个微电子芯片嵌入符合ISO 7816标准的卡基内,做成卡片形式,也是一个嵌入式小系统.由CPU,ROM,RAM及E ...