2016-06-24 72 views
1

我有四個反應的組分:陣營更新父組件時,孩子變化的背景下

  • 的總體父(App或類似)
  • 一個Header孩子,通過App
  • 一個Profile
  • 稱爲
  • A LogoutLink,由Profile調用

我正在使用Auth0實施用戶驗證/登錄系統。當用戶登錄時(通過Header中的登錄按鈕),AppUser對象的Context更改爲包括從Auth0檢索到的所有數據。這個用戶數據可以被需要它的系統的任何部分訪問。

登錄後,UI會自動更新(使用Context更改),以便Header現在顯示「Hey there {name}」而不是「Login」。這也是通向Profile頁面/組件的鏈接(使用React Router的<Link to="/profile></Link>元素)。

Profile頁面有LogoutLink。點擊後,會將用戶註銷,並返回主頁。它還應該自動更新UI,將Header中的消息從「Hey there {name}」更改爲「Login」。這是通過Context再次更改完成的。但是,此功能實際上不起作用 - 用戶已成功註銷,但要查看上述更改,用戶需要刷新整個頁面。 this.context.user沒有被更新併發送回ProfileHeader我知道這是因爲Redux和它的單向數據流(即數據只能向下,而不是向上),但我需要找到解決方法。

這是基本的代碼,我有:

LogoutLink.js

export default class LogoutLink extends React.Component { 

    constructor(props) { 
    super(props); 
    this.onClick = this.onClick.bind(this); 
    this.state = { 
     user: null, 
    }; 
    } 

    static propTypes = { 
    value: React.PropTypes.string, 
    } 

    static contextTypes = { 
    user: React.PropTypes.object, 
    } // get context so this.context is available to get initial user data (before logout) 

    static childContextTypes = { 
    user: React.PropTypes.object, 
    } 

    getChildContext() { 
    return {user: this.state.user} 
    } // these two are for updating context 

    componentWillMount() { 
    this.setState({ user: this.context.user }); 
    } // set the internal LogoutLink state 

    onClick() { 
    this.setState({ user: null }); // set the internal user state to null following logout 
    } 

    renderLogoutLink() { 
    const {value} = this.props; 
    const {user} = this.state; 
    if (user != null) { 
     return <Link to="/profile" onClick={this.onClick}>{value}</Link> 
    } else { 
     return <span>You're already logged out!</span> 
    } 
    } 

    render() { 
    return <span>{this.renderLogoutLink()}</span> 
    } 

} 

Header.js

export default class Header extends React.Component { // eslint-disable-line react/prefer-stateless-function 
    constructor(props) { 
    super(props); 
    this.showLock = this.showLock.bind(this); // lock is the Auth0 module responsible for Login, also passed down by context 
    } 

    static contextTypes = { 
    user: React.PropTypes.object, 
    lock: React.PropTypes.object, 
    } 

    showLock() { 
    const {lock} = this.context; 
    lock.show(); 
    } 

    shouldComponentUpdate(nextProps, nextState, nextContext) { 
    if (this.context.user == null && nextContext.user != null) { 
     return true; 
    } else if (this.context.user != null && nextContext.user == null) { 
     return true; 
    } 
    return false; 
    } // after the LogoutLink is clicked, this still returns false 

    renderLoginButton() { 
    const {user} = this.context; 
    if (user) { 
     const name = user.nickname; 
     return <Link to="/profile">Hey there {name}!</Link> 
    } else { 
     return <button onClick={this.showLock}>Login</button> 
    } 
    } 

    render() { 
    return (
     <header> 
     {this.renderLoginButton()} 
     </header> 
    ); 
    } 
} 

我下面的官方作出反應有關語境和更新它的文檔,發現這裏:https://facebook.github.io/react/docs/context.html

正如我所說我知道爲什麼這不起作用:數據只能以一種方式發送。但我需要找到一種方法來完成這項工作,說實話,我認爲我一直盯着這個太長時間,現在已經沒有選擇,我的大腦有點疲憊。

+0

是什麼nextContext在頭部的值應爲ComponentUpdate。它應該是th e更新了一個 shouldComponentUpdate可能是這裏的罪魁禍首。請檢查nextContext.user –

+0

Hi Piyush - 'nextContext.user'與'this.context.user'等同於'Header'組件'shouldComponentUpdate' - 當'LogoutLink'更改時,它不會改變上下文。 –

回答

1

找到了解決此問題的方法。在我的App.js代碼中,它爲User項目設置了初始上下文,我在User上添加了一個方法來將User設置爲null,然後通過應用程序向下緩存。在註銷鏈接中它調用這個方法。下面是代碼:

App.js

profile.logout =() => { 
    this.setState({ profile: null }); 
} 

getChildContext()方法然後將從此狀態改變用戶上下文:

getChildContext() { 
    return { 
    user: this.state.profile 
    }; 
} 

LogoutLink.js

onClick() { 
    const {user} = this.context; 
    user.logout(); 
} 
0

React「上下文」功能非常有用,但也很複雜且古怪,這就是爲什麼使用它的一些注意事項。特別是,我相信從shouldComponentUpdate返回false的組件會導致較低的組件在上下文內容更改時不更新。

我的建議是儘可能少地使用上下文,並且僅用於而不是更改的數據。將更改數據(如當前用戶)放入Redux xtate中。

+0

謝謝馬克。雖然你說錯誤的'shouldComponentUpdate'會導致較低的組件不更新,我有相反的問題:我想要一個更高的組件更新時,通過更低的組件更改上下文。我認爲在某種程度上(根據Redux),數據只能流下來纔有意義。但這也是令人討厭的,因爲上下文理論上應該是應用程序範圍的。 –

+0

我對上下文的理解仍然非常模糊,所以不要把它當作福音。也就是說,我不認爲這是上下文的作用。據我瞭解,上下文的目的是讓祖先向請求它的任何後代提供一些大部分不變的數據。這不是「應用程序範圍」,除非它是您的最高級組件暴露的內容。這也不是一個後裔與祖先溝通的方式。 – markerikson