下文有项目文件下载
在项目目录中执行 npm install 安装依赖,install start 启动项目,网页会自动打开
index.js
Import React from ' React ' import {render} from ' React-dom ' import {createstore} from ' redux ' import {Provider} from ' re Act-redux ' Import App from './containers/app ' import Todoapp from './reducers ' to store = CreateStore (Todoapp) let RootElement = document.getElementById (' root ') render (<provider store={store}> <app/> </Provider> RootElement)
Action to create functions and constants
actions JS
/* * Action type */export const ADD_TODO = ' Add_todo '; export const Complete_todo = ' Complete_todo '; Export const Set_visibili Ty_filter = ' set_visibility_filter '/* * Other constants */export Const Visibilityfilters = {show_all: ' Show_all ', show_completed: ' Show_completed ', show_active: ' Show_active '};/* * action creates function */export functions Addtodo (text) {return {Type:add_tod O, text}}export function Completetodo (index) {return {Type:complete_todo, index}}export function setvisibilityfilter (filter) {return {type:set_visibility_filter, FILTER}}
Reducers
reducers JS
import { combinereducers } from ' redux ' Import { add_todo, complete_ todo, set_visibility_filter, visibilityfilters } from './actions ' const { Show_all } = visibilityfiltersfunction visibilityfilter (state = SHOW_ALL, Action) { switch (Action.type) { case set_visibility_ filter: return action.filter default: return state }}function todos (state = [], Action) { switch (Action.type) { case ADD_TODO: return [ ...state, { text: action.text, completed: false } ] case COMPLETE_TODO: return [ ...state.slice (0, Action.index), object.assign ({}, state[action.index], { completed: true }), ...state.slice (Action.index &NBSP;+&NBSP;1) ] default: return state }}const todoapp = combinereducers ({ Visibilityfilter, todos}) Export default todoapp
Container components
containers/App.js
import react, { component, proptypes } from ' React ' import { connect } from ' React-redux ' import { addtodo, completetodo, setvisibilityfilter, visibilityfilters } from '. /actions ' import addtodo from '. /components/addtodo ' import todolist from '. /components/todolist ' import footer from '. /components/footer ' Class app extends component { render () { // injected by connect () call: const { Dispatch, visibletodos, visibilityfilter } = this.props return ( <div> < addtodo onaddclick={text => &nbsP; dispatch (Addtodo (text)) } /> <TodoList todos={visibleTodos} Ontodoclick={index => dispatch ( Completetodo (index)) } /> <footer filter={ visibilityfilter} onfilterchange={nextfilter = > dispatch (SetVisibilityFilter ( Nextfilter)) } /> </div> ) }}app.proptypes = { visibletodos: proptypes.arrayof (Proptypes.shape ({ text: proptypes.string.isrequired, completed: proptypes.bool.isrequired }). isrequired). Isrequired, visibilityfilter: proptypes.oneof ([ ' show_all ', ' SHOW_COMPLETED ', ' show_active ' ]. Isrequired}function selecttodos (todos, filter) { switch (filter) { case VisibilityFilters.SHOW_ALL: return todos case visibilityfilters.show_ Completed: return todos.filter (todo => todo.completed) case visibilityfilters.show_active: return todos.filter (todo => !todo.completed) }}// Which props do we want to inject, Given the global state?// note: use https://github.com/faassen/reselect for better performance.function select (state) { return { visibletodos: selecttodos (State.todos, state.visibilityfilter), visibilityfilter: state.visibilityfilter }}// packaging component injection dispatch and state to its default connect (select) (APP) Export default connect (select) (APP)
Presentation components
components/AddTodo.js
import react, { component, proptypes } from ' React ' Export default class addtodo extends component { render () { return ( <div> <input type= ' text ' ref= ' input ' /> < button onclick={(e) => this.handleclick (e)}> Add </button> </div> ) } handleclick (e) { const node = this.refs.input const text = Node.value.trim () this.props.onaddclick (text) node.value = ' }}addtodo.proPtypes = { onaddclick: proptypes.func.isrequired}
components/ Footer. JS
import react, { component, proptypes } from ' React ' Export default class footer extends component { renderfilter (Filter, name) { if (Filter === this.props.filter) { return name } return ( <a href= ' # ' onClick={e => { e.preventdefault () this.props.onfilterchange (filter) }}> {name} </a> ) } render () { return ( <p> show: {' '} {this.renderfilter (' Show_all ', ' all ')} {', '} {this.renderfilter (' show_completed ', ' completed ')} {', '} {this.renderfilter (' SHOW_ACTIVE ', ' Active ')} . </p > ) }}Footer.propTypes = { onFilterChange: Proptypes.func.isrequired, filter: proptypes.oneof ([ ' SHOW_ALL ', ' show_completed ', ' show_active ' ]). IsRequired}
components/ Todo. JS
import react, { component, proptypes } from ' React ' Export default class todo extends component { render () { return ( <li onclick ={this.props.onclick} style={{ textDecoration: this.props.completed ? ' Line-through ' : ' None ', cursor: this.props.completed ? ' default ' : ' pointer ' }}> {this.props.text} </li> ) }}Todo.propTypes = { onClick: Proptypes.func.isrequired, text: proptypeS.string.isrequired, completed: proptypes.bool.isrequired}
components/ Todolist. JS
import react, { component, proptypes } from ' React ' import Todo from './todo ' export default class todolist extends component { Render () { return ( <ul> {this.props.todos.map (Todo, index) => <Todo {...todo} key={index} onclick={() => this.props.ontodoclick (index )} /> )} </ul> ) }}TodoList.propTypes = { onTodoClick: proptypes.func.isrequired, &Nbsp;todos: proptypes.arrayof (Proptypes.shape ({ text: proptypes.string.isrequired, completed: proptypes.bool.isrequired }). isrequired). IsRequired}
React-redux's Todomvc