TodoList.js
import React, { Component, Fragment } from 'react';
import ToDoItem from './ToDoItem';
import Test from './Test';
class ToDoList extends Component {
constructor(props) {
//constructor是一个构造函数,每个类都有,是最先被执行的函数
super(props)
//super(props)指的是要调用父类的构造函数
this.state = {
//this.state指的是父类的状态
inputValue: '',//input框的内容
list: [],//展示的列表
}
//当组件的state或者props发生改变的时候,render函数就会重新执行
this.handleItemDelete = this.handleItemDelete.bind(this)
this.handleInputChange = this.handleInputChange.bind(this)
this.handleButtonChange = this.handleButtonChange.bind(this)
//性能优化
}
//输入框的值发生变化
handleInputChange = (e) => {
// //输入框第一种获取dom的方法
// const value = e.target.value
// // this.setState(() => {
// // return {
// // inputValue: value
// // }
// // })
// this.setState(() => ({ inputValue: value }))
// //新版的react的setState可以接收一个函数,返回一个对象
// //在ES6里面直接返回一个对象,可以不用return,用()
//输入框第二种获取dom的方法,使用ref,不建议使用
const value = this.input.value
this.setState(() => ({ inputValue: value }))
}
//点击提交
handleButtonChange = () => {
const { list, inputValue } = this.state
const newList = [...list, inputValue]
this.setState(() => (
{
list: newList,
inputValue: ''
}
),()=>{
console.log(this.ul.querySelectorAll('div').length)
//查看ul下div的长度
})
//this.setState是一个异步函数
}
//点击内容(删除)
handleItemDelete = (index) => {
this.setState((prevState) => {
const list = [...prevState.list]//拷贝
list.splice(index, 1)
return { list }
})
//setState接受的函数,有一个参数是prevState,表示修改前的state值
}
getToDoItem = () => {
return this.state.list.map((item, index) => {
return (
<div key={index}>
<ToDoItem
content={item}
index={index}
handleItemDelete={this.handleItemDelete}
/>
{/* 父组件向子组件传递内容用属性来传递,子组件通过this.props来获取 */}
</div>
)
})
}
render() {
const { inputValue } = this.state
return (
<Fragment>
{/* Fragment占位符,可以让最外层的div隐藏掉 */}
<div>
<label htmlFor='insertArea'>输入内容</label>
{/* 当label被点击时,浏览器会自动将焦点转移到个label相关的input上 */}
<input id="insertArea"
value={inputValue}
onChange={this.handleInputChange}
ref={(input) => { this.input = input }}>
</input>
{/* input框的值和状态中的inputValue进行绑定 */}
{/* ref里面的函数会自动接收一个参数,就是input */}
<button onClick={this.handleButtonChange}>提交</button>
<ul ref={(ul)=>{this.ul = ul}}>{this.getToDoItem()}</ul>
<Test content={inputValue} />
</div>
</Fragment>
)
}
}
export default ToDoList;
ToDoItem.js
import React, { Component } from 'react';
class ToDoItem extends Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this)
//性能优化
}
shouldComponentUpdate(nextProps,nextState){
if(nextProps.content !== this.props.content){
return true
}else{
return false
}
}
//性能优化,因为父组件每次改变state都会render,导致子组件也会render一遍,这里就判断父组件render的时候
//是否导致content参数发生改变,如果不变,就不render子组件
//nextProps表示的是Props接下来变化成的样子
handleClick = () => {
//点击删除,调用父组件的方法
const { handleItemDelete, index } = this.props
handleItemDelete(index)
}
render() {
const { content } = this.props
return (
<div onClick={this.handleClick}>{content}</div>
)
}
}
export default ToDoItem
Test.js
import React, { Component } from 'react'
class Test extends Component {
//当父组件的render函数被运行时,它的子组件的render都将重新运行
render() {
return <div>{this.props.content}</div>
}
}
export default Test