父组件:TodoList
UI组件:TodoListUI
子组件:TodoItem
现在要做这样一件事情:父组件的DOM元素渲染完全交给UI组件来完成,即每次添加的列表项在UI组件中循环渲染。我们使用Ant Design的List.Item来完成点击列表项就可以删除该项的动作时,就要对父组件传递一个重要参数index
,即列表项的下标,而父组件中仅仅实现Redux工作流并使用了UI组件:
=>Redux工作流:
handleItemDelete(index) {
//action对象创建
const action = getDeleteItemAction(index);
//把action传递给store
store.dispatch(action);
}
=>UI组件的使用:
constructor(props) {
super(props);
this.state = store.getState();
//将this指向在初始化的时候就绑定好
this.handleInputChange = this.handleInputChange.bind(this);
this.handleBtnClick = this.handleBtnClick.bind(this);
this.handleItemDelete = this.handleItemDelete.bind(this);
this.handleStoreChange = this.handleStoreChange.bind(this);
store.subscribe(this.handleStoreChange);// 只要store发生改变,就可以自动执行subscribe中自定义的函数
}
render() {
return (
//UI组件的使用
<TodoListUI
inputValue={this.state.inputValue}
list={this.state.list}
handleInputChange={this.handleInputChange}
handleBtnClick={this.handleBtnClick}
handleItemDelete={this.handleItemDelete}
/>
);
}
如何来完成呢?其实本质问题就是如何在UI组件中使用父组件的handleItemDelete
函数并传递index
。下面介绍UI组件中循环渲染部分的三种写法:
1.使用子组件完成参数传递(推荐但有些复杂)
此时UI组件是TodoItem的父组件,UI组件通过父组件传递过来的属性值来调用handleItemDelete
方法,并通过属性delItem
将该方法传递给TodoItem,将下标index
作为属性传递给TodoItem。于是TodoItem就可以使用父组件TodoList的handleItemDelete(index)
方法
UI组件中的实现:
<List
style={{marginTop: '10px', width: '300px'}}
bordered
dataSource={this.props.list}
renderItem={(item,index) =>(
<TodoItem
index={index}
delItem={this.props.handleItemDelete}
con={item}
/>
)
}
/>
子组件中的实现:
import React,{Component} from 'react';
import {List}from 'antd'
class TodoItem extends Component{
constructor(props){
super(props);
this.handleDelItem=this.handleDelItem.bind(this)//节约性能
}
render() {
const {con}= this.props;
return(
//使用antd的List.Item组件美化
<List.Item
onClick={this.handleDelItem}
>
{/*接收父组件的自定义的con属性*/}
{con}
</List.Item>
)
}
handleDelItem(){
//子组件被点击时,调用父组件传递过来的delItem方法,同时把父组件传递过来的index作为参数传到方法中
//但是子组件不能改变父组件传递过来的内容,否则报错Cannot assign to read only property 'list' of object '#<Object>'
const{delItem,index}=this.props;
delItem(index);
}
}
export default TodoItem
2.不使用子组件,通过箭头函数直接传递参数(推荐)
若直接使用onClick={this.props.handleItemDelete(index)}
,报错:
Render methods should be a pure function of props and state.
而使用箭头函数,空参数返回一个带有参数的函数(从父组件传递过来的属性中使用该函数),此时this.props.handleItemDelete(index)
会自动匹配renderItem
回调的下标
UI组件中的实现:
<List
style={{marginTop: '10px', width: '300px'}}
bordered
dataSource={this.props.list}
renderItem={(item,index) =>(
<List.Item
=>>>箭头函数括号里不能写index,这样的话传递的是event这个事件对象
onClick={()=>{this.props.handleItemDelete(index)}}
>
{item}
</List.Item>
)
}
/>
3.不使用子组件,通过改变this指向实现(不推荐)
这样做避免了这个错误:
Render methods should be a pure function of props and state.
UI组件中的实现:
<List
style={{marginTop: '10px', width: '300px'}}
bordered
dataSource={this.props.list}
renderItem={(item,index) =>(
<List.Item
onClick={this.props.handleItemDelete.bind(this,index)}
>
{item}
</List.Item>
)
}
/>