上回說到共享了變量user,我們發現還遺留了兩個callback,如法炮制,把這兩個callback也丟到共享環境里去。于是乎Provider變成了這個樣子:
<UserContext.Provider value={
{
user: this.state.user,
onLogin: this.loginHandler,
onLogout: this.logoutHandler
}
}>
{
this.state.user
?
(<Main />)
:
(<Login />)
}
</UserContext.Provider>
首先我們看到Provider的value這里我們扔進去了個對象,這個對象里面包含了我們要共享的三個東東。其次我們看到,Main組件和Login組件已經變成了干干凈凈一張大白紙。
我們先來到要用user和onLogout的Menu組件,我們知道Consumer里是個函數,共享變量是通過函數參數傳遞給JSX使用的,上次只有一個user,所以直接傳user就行了,但今天我們丟進去的對象,所以在傳參的時候也要傳遞個對象,這里可以直接用對象解構即可。代碼變成如下樣子:
<UserContext.Consumer>
{
({ user, onLogout }) => (
<div>
<img
src={user.avatar}
onClick={this.toggleMenu}
ref={this.avatarRef}
/>
{this.state.visible && (
<ul>
<li onClick={onLogout}>退出登錄</li>
</ul>
)}
</div>
)
}
</UserContext.Consumer>
再重申一次,丟進去的是個對象,使用時也是個對象,因此在MessageList組件中用到的user要加上{}才行哦。不貼代碼了就。
最后我們來看看Login組件。沒啥可說的,先import進來UserContext,再使用Consumer提取共享變量供組件享用,代碼如下:
<UserContext.Consumer>
{
({ onLogin }) => (
<div>
<form onSubmit={e => submitHandler(e, onLogin)}>
<label>
用戶名
<input
name="username"
value={username}
onChange={inputChangeHandler}
/>
</label>
<label>
密碼
<input
name="password"
type="password"
value={password}
onChange={inputChangeHandler}
/>
</label>
{error && <div>{error.message}</div>}
<button type="submit" disabled={loading}>登錄</button>
</form>
</div>
)
}
</UserContext.Consumer>
這里要說明的是,之前onLogin是在submitHandler函數中用到的,我們是通過props傳遞過來的,所以在函數中直接使用this.props.onLogin沒有問題。但現在onLogin是在JSX中傳遞進來的,怎么給submitHandler函數呢?多加個參數唄,傳給它就好了。
下一講我們要講如何把user的相關操作從App組件中抽取出來成獨立的組件,仔細想想其實user和App組件沒啥關系。它其實就是傳說中的爺爺組件用,爸爸組件用,兒子組件用,孫子組件用的共享變量。