本文小編為大家詳細(xì)介紹“React中的props改變時更新組件的方法是什么”,內(nèi)容詳細(xì),步驟清晰,細(xì)節(jié)處理妥當(dāng),希望這篇“React中的props改變時更新組件的方法是什么”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學(xué)習(xí)新知識吧。
10年積累的成都網(wǎng)站建設(shè)、成都網(wǎng)站設(shè)計經(jīng)驗,可以快速應(yīng)對客戶對網(wǎng)站的新想法和需求。提供各種問題對應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認(rèn)識你,你也不認(rèn)識我。但先網(wǎng)站制作后付款的網(wǎng)站建設(shè)流程,更有景東免費網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。
何時使用派生狀態(tài)
咱們先來看一個比較常見的需求,一個用戶列表,可以新增和編輯用戶,當(dāng)用戶點擊‘新建'
按鈕用戶可以在輸入框中輸入新的用戶名;當(dāng)點擊‘編輯'按鈕的時候,輸入框中顯示被編輯的用戶名,用戶可以修改;當(dāng)用戶點擊‘確定'按鈕的時候用戶列表更新。
class UserInput extends React.Component { state = { user: this.props.user } handleChange = (e) => { this.setState({ user: { ...this.state.user, name: e.target.value } }); } render() { const { onConfirm } = this.props; const { user } = this.state; return ( <div> <input value={user.name || ''} onChange={this.handleChange} /> <button onClick={() => { onConfirm(user) }}>確定</button> </div> ); } } class App extends React.Component { state = { users: [ { id: 0, name: 'bruce' }, { id: 1, name: 'frank' }, { id: 2, name: 'tony' } ], targetUser: {} } onConfirm = (user) => { const { users } = this.state; const target = users.find(u => u.id === user.id); if (target) { this.setState({ users: [ ...users.slice(0, users.indexOf(target)), user, ...users.slice(users.indexOf(target) + 1) ] }); } else { const id = Math.max(...(users.map(u => u.id))) + 1; this.setState({ users: [ ...users, { ...user, id } ] }); } } render() { const { users, targetUser } = this.state; return ( <div> <UserInput user={targetUser} onConfirm={this.onConfirm} /> <ul> { users.map(u => ( <li key={u.id}> {u.name} <button onClick={() => { this.setState({ targetUser: u }) }}>編輯</button> </li> )) } </ul> <button onClick={() => { this.setState({ targetUser: {} }) }}>新建</button> </div> ) } } ReactDOM.render(<App />, document.getElementById('root'));
運行后,效果如圖:
現(xiàn)在點擊‘編輯'和‘新建'按鈕,輸入框中的文字并不會切換,因為點擊‘編輯'和‘更新'時,雖然UserInput
的props改變了但是并沒有觸發(fā)state的更新。所以需要實現(xiàn)props改變引發(fā)state更新,在UserInput
中增加代碼:
componentWillReceiveProps(nextProps) { this.setState({ user: nextProps.user }); }
或者
static getDerivedStateFromProps(props, state) { return { user: props.user }; }
這樣就實現(xiàn)了UserInput
每次接收新的props的時候自動更新state。但是這種實現(xiàn)方式是有問題的。
派生狀態(tài)導(dǎo)致的問題
首先來明確組件的兩個概念:受控數(shù)據(jù)(controlled data lives)和不受控數(shù)據(jù)(uncontrollered data lives)。受控數(shù)據(jù)指的是組件中通過props傳入的數(shù)據(jù),受到父組件的影響;不受控數(shù)據(jù)指的是完全由組件自己管理的狀態(tài),即內(nèi)部狀態(tài)(internal state)。而派生狀態(tài)揉合了兩種數(shù)據(jù)源,當(dāng)兩種數(shù)據(jù)源產(chǎn)生沖突時,問題隨之產(chǎn)生。
問題一
當(dāng)在修改一個用戶的時候,點擊‘確定'按鈕,輸入框里的文字又變成了修改之前的文字。比如我將‘bruce'修改為‘bruce lee',確定后,輸入框中又變成了‘bruce',這是我們不愿意看到的。
出現(xiàn)這個問題的原因是,點擊確定,App會re-render,App又將之前的user作為props傳遞給了UserInput
。我們當(dāng)然可以在每次點擊確定之后將targetUser
重置為一個空對象,但是一旦狀態(tài)多了之后,這樣管理起來非常吃力。
問題二
假設(shè)頁面加載完成后,會異步請求一些數(shù)據(jù)然后更新頁面,如果用戶在請求完成頁面刷新之前已經(jīng)在輸入框中輸入了一些文字,隨著頁面的刷新輸入框中的文字會被清除。
我們可以在App
中加入如下代碼模擬一個異步請求:
componentDidMount() { setTimeout(() => { this.setState({ text: 'fake request' }) }, 5000); }
導(dǎo)致這個問題的原因在于,當(dāng)異步請求完成,setState
后App
會re-render,而組件的componentWillReceiveProps
會在父組件每次render的時候執(zhí)行,而此時傳入的user
是一個空對象,所以UserInput
的內(nèi)容被清空了。而getDerivedStateFromProps
調(diào)用的更頻繁,會在組件每次render的時候調(diào)用,所以也會產(chǎn)生該問題。
為了解決這個問題我們可以在componentWillReceiveProps
中判斷新傳入的user和當(dāng)前的user是否一樣,如果不一樣才設(shè)置state:
componentWillReceiveProps(nextProps) { if (nextProps.user.id !== this.props.user.id) { this.setState({ user: nextProps.user }); } }
更好的解決方案
派生狀態(tài)的數(shù)據(jù)源的不確定性會導(dǎo)致各種問題,那如果每份數(shù)據(jù)有且只被一個component管理應(yīng)該就能避免這些問題了。這種思路有兩種實現(xiàn),一種是數(shù)據(jù)完全由父組件管理,一種是數(shù)據(jù)完全由組件自己管理。下面分別討論:
完全受控組件(fully controlled component)
組件的數(shù)據(jù)完全來自于父組件,組件自己將不需要管理state。我們新建一個完全受控版的UserInput
:
class FullyControlledUserInput extends React.Component { render() { const { user, onConfirm, onChange } = this.props; return ( <div> <input value={user.name || ''} onChange={onChange} /> <button onClick={() => { onConfirm(user) }}>確定</button> </div> ) } }
App中調(diào)用FullyControlledUserInput
的方法如下:
... <FullyControlledUserInput user={targetUser} onChange={(e) => { this.setState({ targetUser: { id: targetUser.id, name: e.target.value } }); }} onConfirm={this.onConfirm} /> ...
現(xiàn)在FullyControlledUserInput
中的所有的數(shù)據(jù)都來源于父組件,由此解決數(shù)據(jù)沖突和被篡改的問題。
完全不受控組件(fully uncontrolled component)
組件的數(shù)據(jù)完全由自己管理,因此componentWillReceiveProps
中的代碼都可以移除,但保留傳入props來設(shè)置state初始值:
class FullyUncontrolledUserInput extends React.Component { state = { user: this.props.user } onChange = (e) => { this.setState({ user: { ...this.state.user, name: e.target.value } }); } render() { const { user } = this.state; const { onConfirm } = this.props; return ( <div> <input value={user.name || ''} onChange={this.onChange} /> <button onClick={() => { onConfirm(user) }}>確定</button> </div> ) } }
當(dāng)傳入的props發(fā)生改變時,我們可以通過傳入一個不一樣的key
來重新創(chuàng)建一個component的實例來實現(xiàn)頁面的更新。App中調(diào)用FullyUncontrolledUserInput
的方法如下::
<FullyUncontrolledUserInput user={targetUser} onConfirm={this.onConfirm} key={targetUser.id} />
大部分情況下,這是更好的解決方案?;蛟S有人會覺得這樣性能會受影響,其實性能并不會變慢多少,而且如果組件的更新邏輯過于復(fù)雜的話,還不如重新創(chuàng)建一個新的組件來的快。
在父組件中調(diào)用子組件的方法設(shè)置state
如果某些情況下沒有合適的屬性作為key
,那么可以傳入一個隨機(jī)數(shù)或者自增的數(shù)字作為key,或者我們可以在組件中定義一個設(shè)置state的方法并通過ref
暴露給父組件使用,比如我們可以在UserInput
中添加:
setNewUserState = (newUser) => { this.setState({ user: newUser }); }
在App中通過ref調(diào)用這個方法:
... <UserInput user={targetUser} onConfirm={this.onConfirm} ref='userInput' /> <ul> { users.map(u => ( <li key={u.id}> {u.name} <button onClick={() => { this.setState({ targetUser: u }); this.refs.userInput.setNewUserState(u); }}> 編輯 </button> </li> )) } </ul> <button onClick={() => { this.setState({ targetUser: {} }); this.refs.userInput.setNewUserState({}); }}> 新建 </button> ...
讀到這里,這篇“React中的props改變時更新組件的方法是什么”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領(lǐng)會,如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。
本文名稱:React中的props改變時更新組件的方法是什么
新聞來源:http://jinyejixie.com/article4/jjpcie.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供虛擬主機(jī)、服務(wù)器托管、用戶體驗、品牌網(wǎng)站建設(shè)、網(wǎng)站制作、做網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)