功能需求
创建一个todolist,输入框输入新增的todo,回车追加到下面的todolist中。
点击todo后面的撤销 将此todo从todolist中删除。
第一版:
class ToDoList extends React.Component{
constructor(props){
super(props);
this.state={
"todoList": [
"do the shopping",
"clean the rooms"
]
};
}
keyDownHandle=(e)=>{
const newTodoList = this.state.todoList;
if(e.keyCode == 13){
newTodoList.push(e.target.value);
this.setState({"todoList": newTodoList});
}
}
redoClick=(e)=>{
const todoList = this.state.todoList;
const delItem = e.target.dataset.item;
todoList.splice(todoList.indexOf(delItem), 1);
this.setState({"todoList": todoList});
}
render(){
const todoList = this.state.todoList;
const listItems = todoList.map((todo) =>
<li key={todo}><span>{todo}<img src="redo.png" onClick={this.redoClick} data-item={todo}/></span></li> );
return(
<div>
<input type="text" onKeyDown={this.keyDownHandle}/>
<ul>{listItems}</ul>
</div>
);
}
}
ReactDOM.render(
<ToDoList />,
document.getElementById("root")
)
第一版:
已实现:
1.追加新的todo
2.从列表中删除todo
未实现:
追加todo之后,input框中的内容没有清空。
第二版
1.this.state中追加inputValue键。
2.render的input value设置为this.state.inputValue,添加onChange事件handle changeHandle。
3.changeHandle中,将input的value更新到todoList的inputValue中。
4.keyDownHandle中,通过this.setState({"inputValue":""})清空input的内容。
class ToDoList extends React.Component{
constructor(props){
super(props);
this.state={
"todoList": [
"do the shopping",
"clean the rooms"
],
"inputValue": "order the newspaper"
};
}
changeHandle=(e)=>{
this.setState({"inputValue":e.target.value});
}
keyDownHandle=(e)=>{
const newTodoList = this.state.todoList;
if(e.keyCode == 13){
newTodoList.push(e.target.value);
this.setState({"todoList": newTodoList, "inputValue":""});
}
}
redoClick=(e)=>{
const todoList = this.state.todoList;
const delItem = e.target.dataset.item; //删除img中的属性data-item={todo},改用this.state
//const delItem = this.state.inputValue;
todoList.splice(todoList.indexOf(delItem), 1);//改变React的state的数据时,拷贝出一个副本,修改副本。--》推荐
this.setState({"todoList": todoList});
}
render(){
const todoList = this.state.todoList;
const listItems = todoList.map((todo) =>
<li key={todo}><span>{todo}<img src="redo.png" data-item={todo} onClick={this.redoClick}/></span></li> );
return(
<div>
<input type="text" onKeyDown={this.keyDownHandle} value={this.state.inputValue} onChange={this.changeHandle}/>
<ul>{listItems}</ul>
</div>
);
}
}
ReactDOM.render(
<ToDoList />,
document.getElementById("root")
)
React不操作Dom元素,改变数据Dom就会重新render。
第二版:
redoClick使用data-item反找index进行删除。不如直接将index传递给redoClick函数。
get到如何从元素中传递参数到函数中onClick={this.redoClick.bind(this,index)}
class ToDoList extends React.Component{
constructor(props){
super(props);
this.state={
"todoList": [
"do the shopping",
"clean the rooms"
],
"inputValue": "order the newspaper"
};
}
changeHandle=(e)=>{
this.setState({"inputValue":e.target.value});
}
keyDownHandle=(e)=>{
const newTodoList = this.state.todoList;
if(e.keyCode == 13){
newTodoList.push(e.target.value);
this.setState({"todoList": newTodoList, "inputValue":""});
}
}
redoClick=(index)=>{
const todoList = this.state.todoList;
todoList.splice(index, 1);//改变React的state的数据时,拷贝出一个副本,修改副本。--》推荐
this.setState({"todoList": todoList});
}
render(){
const todoList = this.state.todoList;
const listItems = todoList.map((todo, index) =>
<li key={index}><span>{todo}<img src="redo.png" onClick={this.redoClick.bind(this,index)}/></span></li> );
return(
<div>
<input type="text" onKeyDown={this.keyDownHandle} value={this.state.inputValue} onChange={this.changeHandle}/>
<ul>{listItems}</ul>
</div>
);
}
}
ReactDOM.render(
<ToDoList />,
document.getElementById("root")
)
第四版:组件拆分
将li封装为TodoItem组件。
父-》子组件间参数的传递:
1.父组件通过属性向子组件传递参数。
2.子组件中使用this.props.XXX接收。
子-》父组件通信:
子组件要调用父组件的方法。
class TodoItem extends React.Component{
clickHandle=()=>{
this.props.itemDeleteHandle();
}
render(){
const index = this.props.index;
const todo = this.props.todo;
return(
<li key={index}><span>{todo}<img src="redo.png" onClick={this.clickHandle}/></span></li>
);
}
}
class ToDoList extends React.Component{
constructor(props){
super(props);
this.state={
"todoList": [
"do the shopping",
"clean the rooms"
],
"inputValue": "order the newspaper"
};
}
changeHandle=(e)=>{
this.setState({"inputValue":e.target.value});
}
keyDownHandle=(e)=>{
const newTodoList = this.state.todoList;
if(e.keyCode == 13){
newTodoList.push(e.target.value);
this.setState({"todoList": newTodoList, "inputValue":""});
}
}
redoClick=(index)=>{
const todoList = this.state.todoList;
todoList.splice(index, 1);//改变React的state的数据时,拷贝出一个副本,修改副本。--》推荐
this.setState({"todoList": todoList});
}
render(){
const todoList = this.state.todoList;
const listItems = todoList.map((todo, index) =>
<TodoItem todo={todo} index={index} itemDeleteHandle={this.redoClick.bind(this, index)}/> );
return(
<div>
<input type="text" onKeyDown={this.keyDownHandle} value={this.state.inputValue} onChange={this.changeHandle}/>
<ul>{listItems}</ul>
</div>
);
}
}
ReactDOM.render(
<ToDoList />,
document.getElementById("root")
)
第五版:性能优化
1.bind去除
2.代码较多不易读时,抽出函数
3.式样美化
4.render只能识别一个JSX,但是有时式样布局的要求使得不能使用div包裹,可以改为使用React.Fragement
class TodoItem extends React.Component{
clickHandle=()=>{
this.props.itemDeleteHandle(this.props.index);
}
render(){
const index = this.props.index;
const todo = this.props.todo;
return(
<div key={index}><span>{todo}<img src="redo.png" onClick={this.clickHandle}/></span></div>
);
}
}
class ToDoList extends React.Component{
constructor(props){
super(props);
this.state={
"todoList": [
"do the shopping",
"clean the rooms"
],
"inputValue": "order the newspaper"
};
}
changeHandle=(e)=>{
this.setState({"inputValue":e.target.value});
}
keyDownHandle=(e)=>{
const newTodoList = this.state.todoList;
if(e.keyCode == 13){
newTodoList.push(e.target.value);
this.setState({"todoList": newTodoList, "inputValue":""});
}
}
redoClick=(index)=>{
const todoList = this.state.todoList;
todoList.splice(index, 1);//改变React的state的数据时,拷贝出一个副本,修改副本。--》推荐
this.setState({"todoList": todoList});
}
getItems=()=>{
const todoList = this.state.todoList;
return todoList.map((todo, index) =>
<TodoItem
todo={todo}
index={index}
itemDeleteHandle={this.redoClick}/>
);
}
render(){
return(
<React.Fragment>
<input className="input" type="text" onKeyDown={this.keyDownHandle} value={this.state.inputValue} onChange={this.changeHandle}/>
<ul>{this.getItems()}</ul>
</React.Fragment>
);
}
}
ReactDOM.render(
<ToDoList />,
document.getElementById("root")
)