Code to be refacted:

  1. const TodoList = ({
  2. todos,
  3. onTodoClick
  4. }) => (
  5. <ul>
  6. {todos.map(todo =>
  7. <Todo
  8. key={todo.id}
  9. {...todo}
  10. onClick={() => onTodoClick(todo.id)}
  11. />
  12. )}
  13. </ul>
  14. );
  15.  
  16. let nextTodoId = 0;
  17. const TodoApp = ({
  18. todos,
  19. visibilityFilter
  20. }) => (
  21. <div>
  22. ...
  23. ...
  24. <TodoList
  25. todos={
  26. getVisibleTodos(
  27. todos,
  28. visibilityFilter
  29. )
  30. }
  31. onTodoClick={id =>
  32. store.dispatch({
  33. type: 'TOGGLE_TODO',
  34. id
  35. })
  36. }
  37. />
  38. ....
  39. </div>
  40. );

Currently we pass the 'todos' and 'onTodoClick' from top container component 'TodoApp', all the way down to the 'Todo' component.

So we want simplfy 'TodoList' Component in TodoApp, create a new container component 'VisibleTodoList'.

In TodoApp:

  1. const TodoApp = ({
  2. todos,
  3. visibilityFilter
  4. }) => (
  5. <div>
  6. <AddTodo
  7. onAddClick={text =>
  8. store.dispatch({
  9. type: 'ADD_TODO',
  10. id: nextTodoId++,
  11. text
  12. })
  13. }
  14. />
  15. <VisibleTodoList />
  16. <Footer />
  17. </div>
  18. );

VisibleTodoList:

  1. class VisibleTodoList extends Component {
  2.  
  3. componentDidMount() {
  4. this.unsubscribe = store.subscribe(() =>
  5. this.forceUpdate()
  6. );
  7. }
  8.  
  9. componentWillUnmount() {
  10. this.unsubscribe();
  11. }
  12.  
  13. render() {
  14.  
  15. const props = this.props;
  16. const state = store.getState();
  17.  
  18. return (
  19. <TodoList
  20. todos={
  21. getVisibleTodos(
  22. state.todos,
  23. state.visibilityFilter
  24. )
  25. }
  26. onTodoClick={id =>
  27. store.dispatch({
  28. type: 'TOGGLE_TODO',
  29. id
  30. })
  31. }
  32. />
  33. );
  34. }
  35. }

----------------

Code:

  1. const todo = (state, action) => {
  2. switch (action.type) {
  3. case 'ADD_TODO':
  4. return {
  5. id: action.id,
  6. text: action.text,
  7. completed: false
  8. };
  9. case 'TOGGLE_TODO':
  10. if (state.id !== action.id) {
  11. return state;
  12. }
  13.  
  14. return {
  15. ...state,
  16. completed: !state.completed
  17. };
  18. default:
  19. return state;
  20. }
  21. };
  22.  
  23. const todos = (state = [], action) => {
  24. switch (action.type) {
  25. case 'ADD_TODO':
  26. return [
  27. ...state,
  28. todo(undefined, action)
  29. ];
  30. case 'TOGGLE_TODO':
  31. return state.map(t =>
  32. todo(t, action)
  33. );
  34. default:
  35. return state;
  36. }
  37. };
  38.  
  39. const visibilityFilter = (
  40. state = 'SHOW_ALL',
  41. action
  42. ) => {
  43. switch (action.type) {
  44. case 'SET_VISIBILITY_FILTER':
  45. return action.filter;
  46. default:
  47. return state;
  48. }
  49. };
  50.  
  51. const { combineReducers } = Redux;
  52. const todoApp = combineReducers({
  53. todos,
  54. visibilityFilter
  55. });
  56.  
  57. const { createStore } = Redux;
  58. const store = createStore(todoApp);
  59.  
  60. const { Component } = React;
  61.  
  62. const Link = ({
  63. active,
  64. children,
  65. onClick
  66. }) => {
  67. if (active) {
  68. return <span>{children}</span>;
  69. }
  70.  
  71. return (
  72. <a href='#'
  73. onClick={e => {
  74. e.preventDefault();
  75. onClick();
  76. }}
  77. >
  78. {children}
  79. </a>
  80. );
  81. };
  82.  
  83. class FilterLink extends Component {
  84. componentDidMount() {
  85. this.unsubscribe = store.subscribe(() =>
  86. this.forceUpdate()
  87. );
  88. }
  89.  
  90. componentWillUnmount() {
  91. this.unsubscribe();
  92. }
  93.  
  94. render() {
  95. const props = this.props;
  96. const state = store.getState();
  97.  
  98. return (
  99. <Link
  100. active={
  101. props.filter ===
  102. state.visibilityFilter
  103. }
  104. onClick={() =>
  105. store.dispatch({
  106. type: 'SET_VISIBILITY_FILTER',
  107. filter: props.filter
  108. })
  109. }
  110. >
  111. {props.children}
  112. </Link>
  113. );
  114. }
  115. }
  116.  
  117. const Footer = () => (
  118. <p>
  119. Show:
  120. {' '}
  121. <FilterLink
  122. filter='SHOW_ALL'
  123. >
  124. All
  125. </FilterLink>
  126. {', '}
  127. <FilterLink
  128. filter='SHOW_ACTIVE'
  129. >
  130. Active
  131. </FilterLink>
  132. {', '}
  133. <FilterLink
  134. filter='SHOW_COMPLETED'
  135. >
  136. Completed
  137. </FilterLink>
  138. </p>
  139. );
  140.  
  141. const Todo = ({
  142. onClick,
  143. completed,
  144. text
  145. }) => (
  146. <li
  147. onClick={onClick}
  148. style={{
  149. textDecoration:
  150. completed ?
  151. 'line-through' :
  152. 'none'
  153. }}
  154. >
  155. {text}
  156. </li>
  157. );
  158.  
  159. const TodoList = ({
  160. todos,
  161. onTodoClick
  162. }) => (
  163. <ul>
  164. {todos.map(todo =>
  165. <Todo
  166. key={todo.id}
  167. {...todo}
  168. onClick={() => onTodoClick(todo.id)}
  169. />
  170. )}
  171. </ul>
  172. );
  173.  
  174. const AddTodo = ({
  175. onAddClick
  176. }) => {
  177. let input;
  178.  
  179. return (
  180. <div>
  181. <input ref={node => {
  182. input = node;
  183. }} />
  184. <button onClick={() => {
  185. onAddClick(input.value);
  186. input.value = '';
  187. }}>
  188. Add Todo
  189. </button>
  190. </div>
  191. );
  192. };
  193.  
  194. const getVisibleTodos = (
  195. todos,
  196. filter
  197. ) => {
  198. switch (filter) {
  199. case 'SHOW_ALL':
  200. return todos;
  201. case 'SHOW_COMPLETED':
  202. return todos.filter(
  203. t => t.completed
  204. );
  205. case 'SHOW_ACTIVE':
  206. return todos.filter(
  207. t => !t.completed
  208. );
  209. }
  210. }
  211.  
  212. class VisibleTodoList extends Component {
  213.  
  214. componentDidMount() {
  215. this.unsubscribe = store.subscribe(() =>
  216. this.forceUpdate()
  217. );
  218. }
  219.  
  220. componentWillUnmount() {
  221. this.unsubscribe();
  222. }
  223.  
  224. render() {
  225.  
  226. const props = this.props;
  227. const state = store.getState();
  228.  
  229. return (
  230. <TodoList
  231. todos={
  232. getVisibleTodos(
  233. state.todos,
  234. state.visibilityFilter
  235. )
  236. }
  237. onTodoClick={id =>
  238. store.dispatch({
  239. type: 'TOGGLE_TODO',
  240. id
  241. })
  242. }
  243. />
  244. );
  245. }
  246. }
  247.  
  248. let nextTodoId = 0;
  249. const TodoApp = ({
  250. todos,
  251. visibilityFilter
  252. }) => (
  253. <div>
  254. <AddTodo
  255. onAddClick={text =>
  256. store.dispatch({
  257. type: 'ADD_TODO',
  258. id: nextTodoId++,
  259. text
  260. })
  261. }
  262. />
  263. <VisibleTodoList />
  264. <Footer />
  265. </div>
  266. );
  267.  
  268. const render = () => {
  269. ReactDOM.render(
  270. <TodoApp
  271. {...store.getState()}
  272. />,
  273. document.getElementById('root')
  274. );
  275. };
  276.  
  277. store.subscribe(render);
  278. render();

[Redux] Extracting Container Components -- VisibleTodoList的更多相关文章

  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 -- Complete

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

  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. win32线程池代码(WinApi/C++)

    win32线程池代码(WinApi/C++) 健壮, 高效,易用,易于扩, 可用于任何C++编译器 //说明, 这段代码我用了很久, 我删除了自动调整规模的代码(因为他还不成熟)/********** ...

  2. Java基础知识强化40:StringBuffer类之StringBuffer的替换功能

    1. StringBuffer的替换功能: public  StringBuffer   replace(int  start,  int  end, String  str): 2. 案例演示: p ...

  3. 自定义ViewGroup 流式布局

    使用 public class MainActivity extends Activity {     @Override     protected void onCreate(Bundle sav ...

  4. ComboGrid( 数据表格下拉框)

    一. 加载方式//class 加载方式<select id="box" class="easyui-combogrid" name="dept& ...

  5. django: form fileupload - 2

    继续介绍文件上传的第二种形式和第三种形式. ------------------------------------------------------------- 第二种形式较简单,直接用 DB ...

  6. 页面传值中get和post区别

    get是把参数数据队列加到提交表单的ACTION属性所指的URL中,值和表单内各个字段一一对应. post是通过HTTP post机制,将表单内各个字段与其内容放置在HTML HEADER内一起传送到 ...

  7. angular 指令 要点解析

    指令可以删繁就简前端的js代码,杜绝重复的js代码和html代码. 下面就对指令的重要属性进行罗列 一.restrict  =  'AECM'  分别指该指令标识位于 attribute属性: < ...

  8. C++拾遗(二)关于变量

    符号常量——预处理方式 例如: #define ZERO 0 会替换程序中所有的ZERO为0,在那些设计为用于C和C++的头文件中,必须使用#define来定义符号常量. 无符号类型 unsigned ...

  9. uva 10609 - Fractal

    题目大意:给出A,B两个点的坐标,以及T,每次找到A.B的四等分点C,D,然后以AB/2为边长,C,D为顶点,构建一个等边三角形,E为另外一个顶点,然后再对C,E:E,D做同样的操作,直到构建的等边三 ...

  10. 学习心得记录:[一]sql安装与配置

    时间:2015年9月13日 02:43:09 科目:mysql的安装 笔记: 准备: 1.首先下载解压版的mysql 2.将下载好的文件放到c:\Program Files\MYSQL下(mysql文 ...