React实现一个ToDoList

父组件ToDoList.js
写注释安住ctrl加反斜杠就会出现{/* */}
dangerouslySetInnerHTML={{__html:item}}两条下划线可以在文本输入的时候识别标签

this.state.list.map((item,index)=>{
   return (
        <li key={index+item}
            onClick={this.deleItem.bind(this,index)}
            dangerouslySetInnerHTML={{__html:item}}
        >
        //{item}当加上dangerouslySetInnerHTML这层的渲染就不需要了 
        </li>
    )
})
import React, { Component,Fragment } from 'react';
import Todoitem from './todoitem';
// Fragment站位符,可以让最外层的div隐藏掉
class TodoList extends Component {
    constructor(props) {
        super(props);
        //绑定this指向,以便后期维护
        this.changeInput = this.changeInput.bind(this)
        this.addList=this.addList.bind(this)
        this.deleItem=this.deleItem.bind(this)
        //当组件的state或者props发生改变的时候,render函数就会重新执行
        this.state = { 
            inputValue:'',
            list:['React','js','css']
         }
    }
   
    render() { 
        return ( 
            <Fragment>
                <label htmlFor='input'>输入内容</label>
                <input 
                    id='input'
                    className='input' 
                    onChange={this.changeInput} 
                    value={this.state.inputValue}
                     type="text"
                    //  ref接受的是一个函数,this.input指向的是input的dom节点
                     ref={(input)=>{this.input=input}}
                  />
                <button onClick={this.addList}>增加</button>
                <ul ref={(ul)=>{this.ul=ul}}>
                    {
                        this.getToDoItem()
                    }
                </ul>
            </Fragment>
         );
    }
    getToDoItem(){
       return  this.state.list.map((item,index)=>{
            return(
                <Todoitem
               		 // 把父组件里面的方法或者数据传递过去给子组件,
               		 //比如下面的content是子组件要接受的键名,{item}是传递给子组件的值
                     list={item}
                     idx={index}
                     deleItem={this.deleItem.bind(this)}//绑定父组件的指向传递给子组件
                    key={index+item}
                 />
            )
        })
    }
    changeInput(e){
        // let value = e.target.value.trim();
        //ref获取到input输入值
        let value = this.input.value.trim();
        this.setState(()=>({
            inputValue:value
        }))
        //数据更新也可以用下面的方便
        // this.setState({
        //     inputValue:value
        // })
    }
    addList(){
        let value = this.state.inputValue;
        if(value){
            this.setState((prevState)=>({
                // prevState相当于this.state
                list:[...prevState.list,value],
                inputValue:''
            }),()=>{
                //setState是异步更新,等setstate执行完成之后再执行以下回调函数
                console.log(this.ul.querySelectorAll('li'))
            })
            // this.setState({
            //     list:[...this.state.list,value],
            //     inputValue:''
            // })
        }
       
    }
    deleItem(idx){
        //immutable
        //state 不允许直接修改state里面的内容
        this.setState((prevState)=>{
            let list = prevState.list;
            list.splice(idx,1);
            return {
                list
            }
        })
        // this.setState({list})
    }
}
export default TodoList;

子组件 ToDoItem.js
获取父组传递过来的值通过this.props加在父组件声明的键名
单项数据流,只能读取,不能直接直接改变,可以通过调用父组件里面的方法来改变

import React, { Component  } from 'react';
import PropTypes from 'prop-types'//npm install prop-types安装一个叫prop-types的第三方包
class TodoItem extends Component {
    constructor(props) {
        super(props);
        this.deleClick=this.deleClick.bind(this)
        this.state = {  }
    }
      //组件被更新之前,会自动执行
      shouldComponentUpdate(nextProps,nextState){
        //nextProps当组件需要更新的时候,希望更新成什么样
        //nextState指的是组件的state会变化成什么样
        //必须要返回一个布尔值
        if(nextProps.list !== this.props.list){
            return true;
        }else{
            return false;
        }
    }
    render() { 
        const {list,test} = this.props;
        return ( 
                <li onClick={this.deleClick}>
                    {test} - {list}
                    {/* this.props.list */}
                </li>
         );
    }
    deleClick(){
        //采用es6的方法进行解构赋值代码优化
        const {deleItem,idx} = this.props;
        deleItem(idx)
        // let idx = this.props.idx;
        // this.props.deleItem(idx)
    }
}
//验证父组件传递过来的值
 TodoItem.propTypes = {
    test:PropTypes.string.isRequired,//isRequired表示该值必须要传
     list:PropTypes.oneOfType([PropTypes.number,PropTypes.string]),//oneOfType可以验证多个值必须要用[]括起来
     deleItem:PropTypes.func,
     idx:PropTypes.number
 }
 //defaultProps设置默认值
 TodoItem.defaultProps={
     test:'hello world'
 }
export default TodoItem;
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值