前言:该实例只是一个简单的react组件化实例,其中有一些写法是便于更好的理解,但在实际情况中可能并不会这样做。会在文章最后做一个总结。
一、效果
二、组件的拆分 ==>> 这里为了突出组件化的思想,把这个小demo拆成了好几个组件(实际项目中可能并不需要,因为比较需求简单)
三、具体代码实现
1. App组件 => index.js
import React, {Component} from 'react';
import './todo.css'
import Lists from './lists'
import Add from './add'
export default class App extends Component{
// constructor(prop){
// super(prop);
// this.state = {
// commentList: [
// {
// name: 'Tom',
// content: 'Hello React!'
// },
// {
// name: 'Blob',
// content: 'React好难啊!'
// },
// ]
// }
// }
state = { //state可以直接写在组件内部,不要写在constructor构造函数内(简写方式)
commentList: [
{
name: 'Tom',
content: 'Hello React!'
},
{
name: 'Blob',
content: 'React好难啊!'
},
]
};
addItem = (comment) => { //新增一条评论,作为回调函数传到add这个子组件中
const {commentList} = this.state;
commentList.unshift(comment);
this.setState({
commentList: commentList
})
};
delItem = (index) => { //删除一条评论,作为回调函数传到ListItem这个子组件中
const {commentList} = this.state;
commentList.splice(index, 1);
this.setState({
commentList: commentList
})
};
render () {
const {commentList} = this.state;
return(
<div>
<div className='titleBox'>
<h2>请发表您对React的看法</h2>
</div>
<div className='commentBox'>
<Add addItemFun={this.addItem} />
<Lists commentList={commentList} delItemFun={this.delItem} />
</div>
</div>
)
}
}
2. Add组件 => add.js
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import './todo.css'
export default class Add extends Component{
static proTypes: {
addItemFun: PropTypes.func.isRequired,
}
constructor(){
super();
this.state = {
name: '',
content: '',
}
}
changeName = (event) => {
this.setState({
name: event.target.value,
})
};
changeContent = (event) => {
this.setState({
content: event.target.value,
})
};
addComment = () => {
console.log(this); //不用箭头函数this为undefined
const {name, content} = this.state;
if(name === ''){
alert('请先填写用户名');
}else if(content === ''){
alert('请先填写评论内容');
}else{
this.props.addItemFun(this.state) //调用回调函数把输入的内容传到父组件进行操作
this.setState({
name: '',
content: '',
})
}
};
render(){
return(
<div className='addBox'>
<p className='userInfo'>
<span>用户名:</span>
<input className='userName' type='text' value={this.state.name} onChange={this.changeName} />
</p>
<p className='userInfo'>
<span>评论:</span>
<textarea className='content' type='text' value={this.state.content} onChange={this.changeContent} />
</p>
<button className='sumbitBtn' onClick={this.addComment}>发布</button>
</div>
)
}
}
3. Lists组件 => lists.js
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import ListItem from './listItem'
export default class Lists extends Component{
static proTypes = {
commentList : PropTypes.array.isRequired,
delItemFun: PropTypes.func.isRequired,
}
render() {
const {commentList, delItemFun} = this.props;
return(
<div className='commentList'>
<h3>评论列表:</h3>
<h4 style={{display: commentList.length ? 'none' : 'block'}}>暂无评论,点击左侧添加评论!!!</h4>
{
commentList.map((item,index) => {
return (<ListItem commentItem={item} key={index} index={index} delItemFun={delItemFun} />)
})
}
</div>
)
}
}
4. ListItem组件 => listItem.js
import React, {Component} from 'react';
import PropTypes from 'prop-types';
export default class ListItem extends Component{
static propTypes = {
commentItem: PropTypes.object.isRequired,
index: PropTypes.number.isRequired,
delItemFun: PropTypes.func.isRequired,
};
delComment = () => {
const {delItemFun, index} = this.props;
delItemFun(index)
};
render(){
return(
<div className='itemBox'>
<p>{this.props.commentItem.name}说:</p>
<p>{this.props.commentItem.content}</p>
<p className='delBtn' onClick={this.delComment}>删除</p>
</div>
)
}
}
5. 样式 => todo.css
.titleBox{
background: #F0F0F0;
padding: 60px 20px 20px 20px;
}
.commentBox{
margin: 0 20px;
display: flex;
}
/*添加评论 add.js*/
.addBox{
flex: 1;
}
.userInfo{
display: flex;
flex-direction: column;
}
.userName, .content{
border: solid 1px #ccc;
height: 24px;
width: 80%;
border-radius: 4px;
padding: 4px;
}
.content{
height: 100px;
}
.sumbitBtn{
border-radius: 4px;
float: right;
margin-right: 20%;
}
.sumbitBtn:after{
width: 0;
height: 0;
clear: both;
}
/*评论列表*/
.commentList{
flex: 1;
}
.commentList > h3{
margin-bottom: 6px;
}
/*评论item*/
.itemBox{
border: solid 1px #ccc;
border-radius: 4px;
margin-bottom: 6px;
padding: 16px;
position: relative;
}
.itemBox > p{
margin: 2px 0;
}
.itemBox > p:nth-child(2){
text-indent: 30px;
}
.delBtn{
position: absolute;
right: 10px;
top: 5px;
font-size: 10px;
border: solid 1px #ccc;
padding: 2px 6px;
border-radius: 4px;
color: #7D9FD1;
cursor: pointer;
}
6. 使用组件 => 项目的入口文件 index.js
import React from 'react';
import ReactDOM from 'react-dom';
// import App from './App';
import App from './pages/todoList/index';
ReactDOM.render(<App />, document.getElementById('root'));
四、总结
1. state的简写方式 => 可以直接写在组件内部,不用写在constructor构造函数内
2. static => 在组件内部使用可以访问到组件类对象,一般用于props的限制(这样不用在组件外部写propTypes)
3. 事件绑定 => 相当于一个回调函数,必须传入一个函数(不能马上调用),如:onClick={this.addComment}
addComment定义的函数里面的this是undefined,必须使用箭头函数定义或者在constructor中将this执行组件实例
addComment 使用箭头函数定义,在绑定箭头的时候不能加()传参,这样会立即调用。但有一个默认参数 event ,即绑 定事件的元素(事件源)
事件绑定最好的方法是在时间绑定是使用箭头函数或者bind(this) ==> 可以传参
箭头函数方式: onClick={ () => this.addComment() } 或者 onClick={ () => { this.addComment() } }
==> 注意: 箭头函数 () => this.addComment() ,这样是相当于一个函数定义(没有调用)
==> 函数体不用大括号: 默认返回结果;函数体如果有多个语句, 需要用{}包围,若有需要返回的内容,需要手动返回
bind(this) 方式:onClick={ this.addComment.bind(this) } ==> bind(this) 默认返回的是函数体,并且不会调用
文章仅为本人学习过程的一个记录,仅供参考,如有问题,欢迎指出!