javascript - react 的問題,標題不知怎么起...
問題描述
我具體描述下問題產生的原因吧。現在有三個組件(暫定a、b、c)去實現一個用戶認證的功能。a組件是父組件(相對b、c,a組件外面還有父組件),負責接收父組件傳遞下來用戶的認證信息,b組件是用戶用來填寫信息的地方,c組件是表示用戶的認證狀態(未認證、審核、已認證、認證失敗,分別對應狀態為0,1,2,-1)。假如用戶認證失敗了,c組件內部會有一個按鈕,讓用戶重新認證(切換b、c組件)。
我一開始寫的時候是這么想的:提取一個狀態到a組件中(暫定show),show的值是根據a組件傳遞下來的認證狀態(props)來確定的,通過show來改變應該展示哪個組件。當用戶認證失敗的時候點擊c組件中的“重新認證”,通過回調函數改變父組件show的狀態,完成b、c組件的切換。問題就出現在這個show上(暫定true顯示b組件,false顯示c組件),show的默認值為true(讓用戶輸入信息)。我在a組件的componentWillReceiveProps里面去改變show的狀態(didMount拿不到props,render里面不能操作state)。現在不論用戶是否通過認證了,a組件加載的時候默認展示的都是b組件,因為componentWillReceiveProps沒有被調用。刷新頁面之后才會展示c組件。現在我能想到的解決辦法就是讓a組件去拿數據,然后確定show的狀態。我想問下各位大神,還有更好的辦法幫我實現這個功能嗎?
補一張圖吧,看的清楚點
問題解答
回答1:a:
//構造器內this.state = { show:true}//class內changeState(){ this.setState({show:false})}//render內const c_props = {changeState}<C {...c_props}/>
c:
onclick(){ this.props.changeState();}回答2:
應該有一個組件去決定是否要進行用戶認證,如果你想讓登錄組件全部包攬這個邏輯,那你需要一個加載狀態,剛開始的時候處于加載中,什么都不顯示。所謂加載就是決定是否要認證(發API請求等等),加載完畢后就可以決定是否要認證。
didMount拿不到props
我100%保證 componentDidMount() 是可以拿到props參數的,通過 this.props 獲取,但是componentDidMount() 只在組件創建時調用一次,通常情況下如果要加載數據就在 componentDidMount() 里執行。
回答3:show為什么要是a組件的state?你把show當作render函數中的一個局部變量就行了。
假定a組件從props里傳遞過來的認證狀態變量命名為 auth,你的 a 組件render方法可以這樣寫:
class A extends Component { render () { let show = this.props.auth === 2; // 0 1 2 -1 return ( <p> {show && <p>component B</p>} {!show && <p>component C</p>} </p> ); }}
========= 更新 =========
第一次沒看到你的C組件居然還有一個回調箭頭來改變A組件的show!
對,這一步也是錯誤的設計。
A組件得到的認證信息是A組件的父組件傳遞下來的,那么這個show就應該要唯一依賴于這一個信息的,C組件具有改變這個認證信息的功能,那么,A組件有義務把這個改變通知給A組件的父組件,而不是私自地悄么聲地改變自己組件的state,即你在這里設定的show這個state,就草草了事。試想,這個時候,A組件得到的props是認證失敗,渲染了C組件,C組件有重新認證的功能,用戶重新認證成功,C組件又通知A組件認證成功了,這個時候A組件要相信誰?props和state就不同步了!更慘的是A組件的父組件,他還傻乎乎地以為自己拿到的是正確的信息,還通過props告訴A組件,用戶認證失敗啦,殊不知A組件已經串通他底下的小弟,把認證信息都給改了!倘若這個時候A組件有個兄弟叫A2組件,A2也通過props從他們共同的父組件接收認證信息,那就會出現A和底下一幫家伙悄悄重新認證了,而A的父親和兄弟還蒙在鼓里,頁面顯示就不一致啦!
正確的設計是,A組件在接收到C組件重新認證成功的事件通知,需要把這個通知繼續往上傳遞,告訴A組件的父組件,父組件接收到這個事件,改變他自己的狀態,進而改變傳遞給A組件的props,A組件props改變,導致A組件重繪,從而replace C with B。
認證信息只能保存一份,你的例子里,認證信息放在A組件的父組件里,因此,要修改這個認證信息,也應該在A組件的父組件里完成。因此,這個show其實只是一個根據props產生的中間變量,根本無需設計成A的state。
如果你用redux就沒有這個疑惑了。
