父组件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;