react案例1:todoList

avatar
作者
筋斗云
阅读量:0

案例效果: 

一、App组件和header输入框的交互:

需求:header输入框中输入活动项,回车之后添加在app组件的state状态中

实现:1、通过在App父组件中添加一个事件,子组件中可以通过this.props.a的方法触发;

        2、子组件中调用方法并通过参数传递需要增加的数据

 (1).App组件

 import React, { Component } from 'react' import Header from './components/Header'; import List from './components/List'; import Footer from './components/Footer'; import './App.css';  class App extends Component {   state={todos:[     {id:'001',name:'吃饭',done:true},     {id:'002',name:'睡觉',done:true},     {id:'003',name:'打代码',done:false},   ]}    a=(info)=>{      const{todos}=this.state      const newTodos=[info,...todos]      console.log('this',this)     //  修改状态      this.setState({todos:newTodos})   }  render(){     return (         <div className="App">           <div className="todo-container">             <div className="todo-wrap">              <Header a={this.a}/>              <List {...this.state}/>              <Footer/>           </div>          </div>         </div>       );  } }  export default App; 

(2)header组件

import React, { Component } from 'react' import {nanoid} from 'nanoid' import './index.css' export default class Header extends Component {     addMessage=(event)=>{         const {keyCode,target}=event         if(keyCode===13){             if(!target.value.trim()){                 alert('输入不能为空')                 return             }             console.log(target.value)             const info={id:nanoid(),name:target.value,done:false}             this.props.a(info)         }     }     render() {       return (         <div>            <div className="todo-header">              <input type="text" onKeyUp={this.addMessage} placeholder="请输入你的任务名称,按回车键确认"/>            </div>         </div>     )   } } 
二、实现鼠标移入移出展示效果
import React, { Component } from 'react' import './index.css'  export default class Item extends Component {     state={mouse:false}    handleMouse=(flag)=>{      return ()=>{         console.log(flag)         this.setState({mouse:flag})         console.log('mouse',this.state.mouse)      }   }   render() {     const {name,done}=this.props     const {mouse}=this.state     return (       <div>         {/* defaultChecked只管一上来是不是勾选,如果是checked则是后续不能修改 */}        {         <li style={{backgroundColor:mouse?'#ddd':'white'}} onMouseEnter={this.handleMouse(true)} onMouseLeave={this.handleMouse(false)}>           <label>             <input type="checkbox" defaultChecked={done}/>             <span>{name}</span>           </label>           <button className="btn btn-danger" style={{display:mouse?'block':'none'}}>{'删除'}</button>         </li>        }                </div>     )   } }
三、选项框修改App中的状态(APP与item爷孙交互)

总结:状态在哪里,修改状态的方法得在哪里。

实现步骤:

1.App中在子组件实例创建的位置绑定事件,并通过方法修改状态中的数据。

2.中间的子组件List中继续传递props中传递的修改状态的方法

 3.item孙组件中触发需要修改状态的事件源,在事件中调用props中传递过来的方法(定义在爷组件中),并传递修改的标识参数方便App组件中的方法修改状态使用。

代码:

App.jsx

 import React, { Component } from 'react' import Header from './components/Header'; import List from './components/List'; import Footer from './components/Footer'; import './App.css';  class App extends Component {   state={todos:[     {id:'001',name:'吃饭',done:true},     {id:'002',name:'睡觉',done:true},     {id:'003',name:'打代码',done:false},   ]}    a=(info)=>{      const{todos}=this.state      const newTodos=[info,...todos]      console.log('this',this)     //  修改状态      this.setState({todos:newTodos})   } //   修改todos中的done   updateTodo=(id,done)=>{     const {todos}=this.state     // 匹配处理数据     const newTodos=todos.map((todoObj)=>{         if(todoObj.id===id) return {...todoObj,done}         else return todoObj     })     // 修改状态     this.setState({todos:newTodos})   }  render(){     return (         <div className="App">           <div className="todo-container">             <div className="todo-wrap">              <Header a={this.a}/>              <List {...this.state} updateTodo={this.updateTodo}/>              <Footer/>           </div>          </div>         </div>       );  } }  export default App; 

 list.jsx

  render() {     console.log('list',this.props)     const {todos,updateTodo}=this.props     return (       <div>          <ul className="todo-main">             {todos.map((item)=>(   <Item  key={item.id} {...item} updateTodo={updateTodo} />) )}          </ul>       </div>     )   }

Item.jsx

import React, { Component } from 'react' import './index.css'  export default class Item extends Component {        state={mouse:false}    handleMouse=(flag)=>{      return ()=>{         console.log(flag)         this.setState({mouse:flag})         console.log('mouse',this.state.mouse)      }   } //  修改App组件中todos列表数据中的done  changeHandle=(event)=>{     const {id,updateTodo}=this.props     console.log(event.target.checked)     updateTodo(id,event.target.checked)   }   render() {     const {name,done}=this.props     const {mouse}=this.state     return (       <div>         {/* defaultChecked只管一上来是不是勾选,如果是checked则是后续不能修改 */}        {         <li style={{backgroundColor:mouse?'#ddd':'white'}} onMouseEnter={this.handleMouse(true)} onMouseLeave={this.handleMouse(false)}>           <label>             <input type="checkbox" defaultChecked={done} onChange={this.changeHandle}/>             <span>{name}</span>           </label>           <button className="btn btn-danger" style={{display:mouse?'block':'none'}}>{'删除'}</button>         </li>        }                </div>     )   } }

四、对props进行类型限制 

安装库:npm i prop-types

引用:import PropTypes from "prop-types"

五、实现删除功能

1、状态所在组件中绑定删除事件,并实现删除逻辑

2、子组件或孙组件中触发事件源并调用app组件中修改状态的方法。

 

 六、实现底部全选功能和删除已完成任务

代码: 

 import React, { Component } from 'react' import Header from './components/Header'; import List from './components/List'; import Footer from './components/Footer';  import './App.css';  class App extends Component {   state={todos:[     {id:'001',name:'吃饭',done:true},     {id:'002',name:'睡觉',done:true},     {id:'003',name:'打代码',done:false},   ]}    a=(info)=>{      const{todos}=this.state      const newTodos=[info,...todos]      console.log('this',this)     //  修改状态      this.setState({todos:newTodos})   } //   修改todos中的done   updateTodo=(id,done)=>{     const {todos}=this.state     // 匹配处理数据     const newTodos=todos.map((todoObj)=>{         if(todoObj.id===id) return {...todoObj,done}         else return todoObj     })     // 修改状态     this.setState({todos:newTodos})   }  //  删除todo   deleteTodo=(id)=>{     const {todos}=this.state     if(window.confirm('您确定删除吗?')){         const newTodos=todos.filter(item=>item.id!==id)         this.setState({todos:newTodos})     }       } //   全选按钮   checkAllTodo=(done)=>{     const {todos}=this.state     const newTodos=todos.map(todo=>{return {...todo,done}})     this.setState({todos:newTodos})   } //   删除已完成任务   deleteDone=()=>{     const {todos}=this.state     const newTodos=todos.filter(todo=>{         return !todo.done     })     this.setState({todos:newTodos})   }  render(){     return (         <div className="App">           <div className="todo-container">             <div className="todo-wrap">              <Header a={this.a}/>              <List {...this.state} updateTodo={this.updateTodo} deleteTodo={this.deleteTodo}/>              <Footer {...this.state} checkAllTodo={this.checkAllTodo} deleteDone={this.deleteDone}/>           </div>          </div>         </div>       );  } }  export default App; 

footer:

import React, { Component } from 'react' import './index.css'  export default class Footer extends Component {     // 全选按钮     changeAll=(event)=>{             this.props.checkAllTodo(event.target.checked)     }     // 删除已完成     deleteDone=()=>{         this.props.deleteDone()     }   render() {     const {todos}=this.props     const total=todos.length     const checkedCount=todos.reduce((pre,cur)=>{return pre+=cur.done?1:0},0)     return (       <div>          <div className="todo-footer">            <label>             <input type="checkbox" checked={total===checkedCount&&total>0?true:false} onChange={this.changeAll}/>           </label>           <span>             <span>已完成{checkedCount}</span> / 全部{total}           </span>          <button className="btn btn-danger" onClick={this.deleteDone}>清除已完成任务</button>       </div>       </div>     )   } } 

 

 七、总结案例:

1、拆分组件、实现静态组件,注意:className,style的写法

2、动态初始化列表,如何确定将数据放在那个组件的state中?

-----某个组件使用:放在自身的state中

-----某些组件使用:放在他们共同的父组件state中(官方称此操作为:状态提升)

3.关于父子之间通信:

   1.【父组件】给【子组件】传递数据:通过props传递

   2.【子组件】给【父组件】传递数据:通过props传递,要求父提前给子传递一个函数

4.注意defaultChecked和checked的区别,类似的还有:defaultValue和value

5.状态在哪里,操作状态的方法就在哪里

    广告一刻

    为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!