欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

react 组件简单实例 — todoList

程序员文章站 2022-07-01 18:28:15
...

前言:该实例只是一个简单的react组件化实例,其中有一些写法是便于更好的理解,但在实际情况中可能并不会这样做。会在文章最后做一个总结。

一、效果

react 组件简单实例 — todoList

二、组件的拆分  ==>> 这里为了突出组件化的思想,把这个小demo拆成了好几个组件(实际项目中可能并不需要,因为比较需求简单)

react 组件简单实例 — todoList

三、具体代码实现

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) 默认返回的是函数体,并且不会调用

                

文章仅为本人学习过程的一个记录,仅供参考,如有问题,欢迎指出!