Code to be refactored:
let nextTodoId = 0;class TodoApp extends Component { render() { const { todos, visibilityFilter } = this.props; const visibleTodos = getVisibleTodos( todos, visibilityFilter ); return ({ this.input = node; }} />); }}{visibleTodos.map(todo =>
- { store.dispatch({ type: 'TOGGLE_TODO', id: todo.id }); }} style={ { textDecoration: todo.completed ? 'line-through' : 'none' }}> {todo.text}
)}Show: {' '}
All {', '}Active {', '}Completed
const FilterLink = ({ filter, currentFilter, children}) => { if (filter === currentFilter) { return {children}; } return ( { e.preventDefault(); store.dispatch({ type: 'SET_VISIBILITY_FILTER', filter }); }} > {children} );};
Refactor footer part into a functional component, which contains all these three filter links. Pass in visibilityFilter as props:
const Footer = ({ visibilityFilter}) => (Show: {
' '}All {', '}Active {', '}Completed );
In the FilterLink, we want it to be presentational components. However, the filter link includes a short dispatch call. I am replacing it with an on click call. I pass the filter as the single parameter for the calling component's convenience. I add on click to the props.
const FilterLink = ({ filter, currentFilter, children, onFilterClick}) => { if (filter === currentFilter) { return {children}; } return ( { e.preventDefault(); onFilterClick(filter); }} > {children} );};
const Footer = ({ visibilityFilter, onFilterClick}) => (Show: {
' '}All {', '}Active {', '}Completed );
-----------------------------------
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;/** Functional compoment, persental compoment: doesn't need to know what to do, just show the interface, call the callback function.*/const AddTodo = ({ onAddTodo}) => { let input; return ({ input = node; }} />);}/* Functional component */const Footer = ({ visibilityFilter, onFilterClick}) => (Show: {
' '}All {', '}Active {', '}Completed );const FilterLink = ({ filter, currentFilter, children, onFilterClick}) => { if (filter === currentFilter) { return {children}; } return ( { e.preventDefault(); onFilterClick(filter); }} > {children} );};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;class TodoApp extends Component { render() { const { todos, visibilityFilter } = this.props; const visibleTodos = getVisibleTodos( todos, visibilityFilter ); return (); }}const render = () => { ReactDOM.render(store.dispatch({ type: 'ADD_TODO', id: nextTodoId++, text }) } /> {visibleTodos.map(todo =>
- { store.dispatch({ type: 'TOGGLE_TODO', id: todo.id }); }} style={ { textDecoration: todo.completed ? 'line-through' : 'none' }}> {todo.text}
)}, document.getElementById('root') );};store.subscribe(render);render();