React父元件和子元件用props傳值
阿新 • • 發佈:2018-12-18
轉載地址: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;*/ }