1. 程式人生 > >React父元件和子元件用props傳值

React父元件和子元件用props傳值

轉載地址:https://www.cnblogs.com/Scar007/p/8060334.html

import React,{Component} from 'react';
import {render} from 'react-dom';
import './comprehensive.css'

/*
 * 一個重要問題知識點:
 *可以看到這個CommentInput元件和CommentList元件都是兩個子元件,但是開始是兩個毫不相干的子元件,我們想讓他們建立連線,但是同為兩個子級元件之間是沒法直接傳值的,這時候他們的父級元件CommentApp就起到了一個橋樑的作用
 * ->當用戶點擊發布按鈕的時候我們將CommentInput中的state當中最新的評論資料傳遞給父級元件CommentApp,然後從父級元件CommentApp傳給子元件CommentList進行渲染
 *
 * 問題來了:那麼子級CommentInput怎麼向父級CommentApp傳值呢?
 *   父元件CommentApp只需要通過props給子元件CommentInput傳入一個回撥函式,當用戶點擊發布按鈕的時候CommentInput呼叫props中的回撥函式並將state傳入該函式即可
 */

//這個是commentInput子元件,負責使用者輸入的區域
class CommentInput extends Component{
    //這裡初始化一個state值來儲存使用者名稱(username)值和評論內容(content)
    //但是自行設定一個初始化的引數之後就不能從介面中輸入了,因為輸入控制元件被設定成了固定值,永遠以設定的為準。
    constructor(){
        super();
        this.state={
            username:'',
            content:''
        }
    }

    //為了解決被控問題,所以就要setState一下,監聽輸入框中的onChange事件,獲取到使用者輸入的內容之後用setState更新一下狀態,這樣input裡邊的內容才會發生改變。下同
    handleUsernameChange=(event)=>{
        this.setState({
            //這裡我們通過event.target.value獲取到輸入框中的內容,並通過setState把它設定到state.username中,這樣內容就會更新,輸入就再沒問題了。下同
            username:event.target.value
        })
    };

    handleContentChange=(event)=>{
        this.setState({
            content:event.target.value
        })
    };

    handleSubmit=()=>{
        //這個方法判斷props中是否傳入了onSubmit屬性,有的話就用該函式,並把使用者輸入的資料都傳給該函式
        if(this.props.onSubmit){
            const {username,content}=this.state;
            this.props.onSubmit({
                username,content
            })
        }
        //增加使用者體驗,提交後清空原來的值
        this.setState({
            username:'',
            content:''
        })
    };

    render(){
        return(
            <div className="comment-input">
                <div className="comment-field">
                    <span className="comment-field-name">使用者名稱:</span>
                    <div className="comment-field-input">
                        //上邊是設定state值初始化,這裡取值就用this.state.XXX,下邊的評論內容同理
                        //這裡加上onChange事件就是為了監聽input的值是否發生改變,從而更新狀態
                        <input type="text" value={this.state.username}
                               onChange={this.handleUsernameChange}
                        />
                    </div>
                </div>
                <div className="comment-field">
                    <span className="comment-field-name">評論內容</span>
                    <div className="comment-field-input">
                        <textarea value={this.state.content}
                                  onChange={this.handleContentChange}
                        />
                    </div>
                </div>
                <div className="comment-field-button">
                    //給按鈕新增點選事件
                    <button onClick={this.handleSubmit}>釋出</button>
                </div>
            </div>
        )
    }
}

//評論列表子元件
class CommentList extends Component{
    //這裡給元件加上defaultProps防止comments不傳而報錯的情況
    static defaultProps={
        comments:[]
    };

    render(){
        return(
            <div>
                //遍歷陣列將值傳遞給Comment
                {this.props.comments.map((comment,index)=>{
                    return <Comment comment={comment} key={index}/>
                })}
            </div>
        )
    }
}

//評論列表中的每個單獨項,這個元件被commentList所用
class Comment extends Component{
    render(){
        return(
            //接收到CommentList傳遞過來的每一條資料然後將其渲染在頁面上
            <div className="comment">
                <div className="comment-user">
                    <span className="comment-username">{this.props.comment.username}</span>
                </div>
                <p>{this.props.comment.content}</p>
            </div>
        )
    }
}


//評論功能整體用這個元件包起來,包括commentInput區域和commentList區域
class CommentApp extends Component{
    //在這裡初始化一個數組,來儲存所有的評論資料,並且通過props把它傳遞給CommentList
    constructor(){
        super();
        this.state={
            comments:[]
        }
    }

    handleSubmitComment=(comment)=>{
        //當用戶釋出評論的時候就把資料插入到comment中,然後通過setState將資料更新到頁面上
        this.state.comments.push(comment);
        this.setState({
            comments:this.state.comments
        })
    };

    render(){
        return(
            <div className="wrapper">
                //內部引入需要的子元件
                //在這個父元件裡給CommentInput子元件傳入一個onSubmit的屬性,這個屬性是CommentApp的一個方法,這樣CommentInput就可以呼叫this.props.onSubmit(...)將資料傳遞給CommentApp
                <CommentInput onSubmit={this.handleSubmitComment}/>
                <CommentList comments={this.state.comments}/>
            </div>
        )
    }
}

class Index extends Component{
    render(){
        return(
            <div>
                <CommentApp/>
            </div>
        )
    }
}

render(<Index/>,document.getElementById('root'));

複製程式碼

複製程式碼

body {
    margin: 0;
    padding: 0;
    font-family: sans-serif;
    background-color: #fbfbfb;
}
.wrapper {
    width: 500px;
    margin: 10px auto;
    font-size: 14px;
    background-color: #fff;
    border: 1px solid #f1f1f1;
    padding: 20px;
}
/* 評論框樣式 */
.comment-input {
    background-color: #fff;
    border: 1px solid #f1f1f1;
    padding: 20px;
    margin-bottom: 10px;
}
.comment-field {
    margin-bottom: 15px;
    display: flex;
}
.comment-field .comment-field-name {
    display: flex;
    flex-basis: 100px;
    font-size: 14px;
}
.comment-field .comment-field-input {
    display: flex;
    flex: 1;
}
.comment-field-input input,
.comment-field-input textarea {
    border: 1px solid #e6e6e6;
    border-radius: 3px;
    padding: 5px;
    outline: none;
    font-size: 14px;
    resize: none;
    flex: 1;
}
.comment-field-input textarea {
    height: 100px;
}
.comment-field-button {
    display: flex;
    justify-content: flex-end;
}
.comment-field-button button {
    padding: 5px 10px;
    width: 80px;
    border: none;
    border-radius: 3px;
    background-color: #00a3cf;
    color: #fff;
    outline: none;
    cursor: pointer;
}
.comment-field-button button:active {
    background: #13c1f1;
}
/* 評論列表樣式 */
.comment-list {
    background-color: #fff;
    border: 1px solid #f1f1f1;
    padding: 20px;
}
/* 評論元件樣式 */
.comment {
    display: flex;
    border-bottom: 1px solid #f1f1f1;
    margin-bottom: 10px;
    padding-bottom: 10px;
    min-height: 50px;
}
.comment .comment-user {
    flex-shrink: 0;
}
.comment span {
    color: #00a3cf;
    font-style: italic;
}
.comment p {
    margin: 0;
    /*text-indent: 2em;*/
}