React学习笔记_dotomvc例子

来源:互联网 发布:中国征兵人口数据 编辑:程序博客网 时间:2024/05/17 06:39

todoMvc 例子

一、reducer

combineReducers

const rootReducer = combineReducers({  todos})

初始化:

const initialState = [  {    text: 'Use Redux',    completed: false,    id: 0  }]

添加记录

  • 计算ID: maxId + 1
  • 设置值
    case ADD_TODO:      return [        ...state,        {          id: state.reduce((maxId, todo) => Math.max(todo.id, maxId), -1) + 1,          completed: false,          text: action.text        }      ]

根据id 删除

    case DELETE_TODO:      return state.filter(todo =>        todo.id !== action.id      )

修改text

    case EDIT_TODO:      return state.map(todo =>        todo.id === action.id ?          { ...todo, text: action.text } :          todo      )

设置状态

    case COMPLETE_TODO:      return state.map(todo =>        todo.id === action.id ?          { ...todo, completed: !todo.completed } :          todo      )

设置全选

    case COMPLETE_ALL:      const areAllMarked = state.every(todo => todo.completed)      return state.map(todo => ({        ...todo,        completed: !areAllMarked      }))

清除状态是 completed 的记录

    case CLEAR_COMPLETED:      return state.filter(todo => todo.completed === false)

二、设置常量

ActionTypes.js

export const ADD_TODO = 'ADD_TODO'export const DELETE_TODO = 'DELETE_TODO'export const EDIT_TODO = 'EDIT_TODO'export const COMPLETE_TODO = 'COMPLETE_TODO'export const COMPLETE_ALL = 'COMPLETE_ALL'export const CLEAR_COMPLETED = 'CLEAR_COMPLETED'

TodoFilters.js

export const SHOW_ALL = 'show_all'export const SHOW_COMPLETED = 'show_completed'export const SHOW_ACTIVE = 'show_active'

三、设置Action

import * as types from '../constants/ActionTypes'export const addTodo = text => ({ type: types.ADD_TODO, text })export const deleteTodo = id => ({ type: types.DELETE_TODO, id })export const editTodo = (id, text) => ({ type: types.EDIT_TODO, id, text })export const completeTodo = id => ({ type: types.COMPLETE_TODO, id })export const completeAll = () => ({ type: types.COMPLETE_ALL })export const clearCompleted = () => ({ type: types.CLEAR_COMPLETED })

设置comtainers

mapStateToProps 
mapDispatchToProps 

 const App = ({todos, actions}) => (  <div>    <Header addTodo={actions.addTodo} />    <MainSection todos={todos} actions={actions} />  </div>)const mapStateToProps = state => ({  todos: state.todos})const mapDispatchToProps = dispatch => ({    actions: bindActionCreators(TodoActions, dispatch)})export default connect(  mapStateToProps,  mapDispatchToProps)(App)

四、component

Header.js

  • handleSave 保存 dispatch(action)
export default class Header extends Component {  handleSave = text => {    if (text.length !== 0) {      this.props.addTodo(text)    }  }  render() {    return (      <header className="header">        <h1>todos</h1>        <TodoTextInput newTodo                       onSave={this.handleSave}                       placeholder="What needs to be done?" />      </header>    )  }}

TodoTextInput

  • state 设置初始状态
  • handleSubmit 提交 dispatch(action)
  • handleChange handleBlur 组件内部事件,处理组件内部input 值改变后更新内部组件的state,重新渲染
export default class TodoTextInput extends Component {  state = {    text: this.props.text || ''  }  handleSubmit = e => {    const text = e.target.value.trim()    if (e.which === 13) {      this.props.onSave(text)      if (this.props.newTodo) {        this.setState({ text: '' })      }    }  }  handleChange = e => {    this.setState({ text: e.target.value })  }  handleBlur = e => {    if (!this.props.newTodo) {      this.props.onSave(e.target.value)    }  }  render() {    return (      <input className={        classnames({          edit: this.props.editing,          'new-todo': this.props.newTodo        })}        type="text"        placeholder={this.props.placeholder}        autoFocus="true"        value={this.state.text}        onBlur={this.handleBlur}        onChange={this.handleChange}        onKeyDown={this.handleSubmit} />    )  }}

五、MainSection 列表

  • 全选
  • 列表 全部、未完成、已完成
  • 列表底部:未完成数量。 切换列表查询状态
  • state 初始状态:显示全部记录
  • handleClearCompleted 清除已经完成的记录,dispatch actions
  • handleShow 根据状态改变列表展示,内部事件。
  • renderToggleAll全选
  • renderFooter 列表底部
const TODO_FILTERS = {  [SHOW_ALL]: () => true,  [SHOW_ACTIVE]: todo => !todo.completed,  [SHOW_COMPLETED]: todo => todo.completed}export default class MainSection extends Component {  state = { filter: SHOW_ALL }  handleClearCompleted = () => {    this.props.actions.clearCompleted()  }  handleShow = filter => {    this.setState({ filter })  }  renderToggleAll(completedCount) {    const { todos, actions } = this.props    if (todos.length > 0) {      return (        <span>          <input className="toggle-all"                 type="checkbox"                 checked={completedCount === todos.length}                 />          <label onClick={actions.completeAll}/>        </span>      )    }  }  renderFooter(completedCount) {    const { todos } = this.props    const { filter } = this.state    const activeCount = todos.length - completedCount    if (todos.length) {      return (        <Footer completedCount={completedCount}                activeCount={activeCount}                filter={filter}                onClearCompleted={this.handleClearCompleted}                onShow={this.handleShow} />      )    }  }  render() {    const { todos, actions } = this.props    const { filter } = this.state    const filteredTodos = todos.filter(TODO_FILTERS[filter])    const completedCount = todos.reduce((count, todo) =>      todo.completed ? count + 1 : count,      0    )    return (      <section className="main">        {this.renderToggleAll(completedCount)}        <ul className="todo-list">          {filteredTodos.map(todo =>            <TodoItem key={todo.id} todo={todo} {...actions} />          )}        </ul>        {this.renderFooter(completedCount)}      </section>    )  }}

六、TodoItem 列表项

  • state 初始状态,不能编辑
  • handleDoubleClick 双击后,可编辑
  • handleSave 编辑状态下,修改 dispatch action
  • render 渲染,根据editing 是否可编辑渲染不同的组件
export default class TodoItem extends Component {  state = {    editing: false  }  handleDoubleClick = () => {    this.setState({ editing: true })  }  handleSave = (id, text) => {    if (text.length === 0) {      this.props.deleteTodo(id)    } else {      this.props.editTodo(id, text)    }    this.setState({ editing: false })  }  render() {    const { todo, completeTodo, deleteTodo } = this.props    let element    if (this.state.editing) {      element = (        <TodoTextInput text={todo.text}                       editing={this.state.editing}                       onSave={(text) => this.handleSave(todo.id, text)} />      )    } else {      element = (        <div className="view">          <input className="toggle"                 type="checkbox"                 checked={todo.completed}                 onChange={() => completeTodo(todo.id)} />          <label onDoubleClick={this.handleDoubleClick}>            {todo.text}          </label>          <button className="destroy"                  onClick={() => deleteTodo(todo.id)} />        </div>      )    }    return (      <li className={classnames({        completed: todo.completed,        editing: this.state.editing      })}>        {element}      </li>    )  }}

七、Footer底部

  • renderTodoCount 显示未处理条数
  • renderFilterLink 状态 button 可切换状态: ALL、Active、Completed
  • renderClearButton 清除 Completed 状态的数据,dispatch action
const FILTER_TITLES = {  [SHOW_ALL]: 'All',  [SHOW_ACTIVE]: 'Active',  [SHOW_COMPLETED]: 'Completed'}export default class Footer extends Component {  renderTodoCount() {    const { activeCount } = this.props    const itemWord = activeCount === 1 ? 'item' : 'items'    return (      <span className="todo-count">        <strong>{activeCount || 'No'}</strong> {itemWord} left      </span>    )  }  renderFilterLink(filter) {    const title = FILTER_TITLES[filter]    const { filter: selectedFilter, onShow } = this.props    return (      <a className={classnames({ selected: filter === selectedFilter })}         style={{ cursor: 'pointer' }}         onClick={() => onShow(filter)}>        {title}      </a>    )  }  renderClearButton() {    const { completedCount, onClearCompleted } = this.props    if (completedCount > 0) {      return (        <button className="clear-completed"                onClick={onClearCompleted} >          Clear completed        </button>      )    }  }  render() {    return (      <footer className="footer">        {this.renderTodoCount()}        <ul className="filters">          {[ SHOW_ALL, SHOW_ACTIVE, SHOW_COMPLETED ].map(filter =>            <li key={filter}>              {this.renderFilterLink(filter)}            </li>          )}        </ul>        {this.renderClearButton()}      </footer>    )  }}
原创粉丝点击