2016-07-07 38 views
0

我有這個Protected HOC。其目的是在用戶通過身份驗證時僅呈現其WrappedComponent。否則應該呈現AuthenticateComponent(通常是登錄組件)。包裝組件仍然呈現,當REDX狀態說不應該

import React from "react" 

const PROPTYPES = { 
    authenticated: React.PropTypes.bool.isRequired, 
} 
export default (WrappedComponent, AuthenticateComponent) => { 
    let Protected = (props) => (
    props.authenticated 
    ? <WrappedComponent {...props}/> 
    : <AuthenticateComponent {...props}/> 
) 
    Protected.propTypes = PROPTYPES 
    return Protected 
} 

該組件的道具來自一個連接Redux的容器組件

const AccountContainer = ({ children }) => (
    <div>{children}</div> 
) 
const select = state => state.account 
export default connect(select, { refreshUser, logout })(Protected(AccountContainer, LoginContainer)) 

account減速看起來是這樣的:

function authenticated(state = false, action) { 
    switch (action.type) { 
    case actions.START_SIGNUP_SUCCESS: 
    case actions.LOGIN_SUCCESS: 
     return true 
    case actions.LOGIN_ERROR: 
    case actions.START_SIGNUP_ERROR: 
    case actions.LOGOUT_SUCCESS: 
     return false 
    default: 
     return state 
    } 
} 

... 

export default combineReducers({ 
    authenticated, 
    access_token, 
    loggingIn, 
    user, 
    error, 
}) 

現在情況發生在LOGOUT動作設定state.account.authenticated屬性設置爲false,但仍然呈現WrappedComponent。它訪問account的各種其他屬性,並且它們都已被清除,組件未檢查和期望。 WrappedComponent假定當它被呈現時,account狀態仍然是authenticated並且因此是有效的。

我想知道可能是什麼樣的競爭條件?

回答

1

我不知道沒有看到代碼,但它看起來像你的減速器改變狀態。減速器不應該改變狀態。它應該改變一個擁有正確屬性的新狀態。

其中的重點是防止競態條件和其他異常情況。

React Redux經過精心設計,可以防止您在此處看到的各種問題。它確實需要您遵守Redux規則。主要的是減速機必須是纔是純功能。

如果您的reducer修改舊狀態並返回,Redux沒有簡單的方法可以看到您對該狀態進行了修改。實際上它會假設沒有改變。因爲沒有東西會被重新渲染。

編輯:

你減速看起來不錯,儘管我看不到如何account減速時用於其他地方,我認爲它的罰款以及。

我認爲問題在於你的組件確實沒有渲染,但渲染方法仍然在LOGOUT上被調用。正在發生的事情是,如果該子組件需要這種渲染,那麼React將愉快地呈現子組件。並且由於connectstore掛鉤,因此會發生這種情況。

當你的狀態變化,connect將通過調用mapStateToProps重新評估的WrappedComponentprops,它會發現,這些道具已經改變(因爲不再登錄,因此該數據是不同的比以前) 。 Connect會指示React重新渲染WrappedComponent。 React會做到這一點。然後,您的render方法反過來可能與其傳遞的數據有關,因爲它的無效數據僅用於用戶登錄時使用的數據。

解決方法是簡單地使用虛擬參數退出渲染<div/>。這個div,一個虛擬的DOM元素,實際上永遠不會把它放到DOM中。反應緩存元素並批量更新DOM。因此,React在將它合併到DOM之前修剪整個WrappedComponent,不幸的是,在它已經呈現新版本之後。

請注意,Redux與Connect結合在一起真的是罪魁禍首,因爲Redux沒有組件的概念,因此可以不考慮它們,而Connect會按照它創建的順序訂閱商店,並且該商店會按照訂購的順序通知組件。

最終訂單取決於渲染順序和掛載順序,許多組件在決定此順序時發揮作用。它根本不穩定,因此不應該被指望。

當你建立連接的組件,請務必寫你mapStateToProps採取任何有效狀態,並從這些對象組件編譯有效道具。無論是添加虛擬值還是更改組件本身以使其傳遞給它的任何內容都有效,允許所有有效狀態解析爲有效道具是非常重要的,即使這些道具所用的組件無意顯示。通過這種方式,您可以防止由於無效道具導致的錯誤,這些道具實際上是由有效狀態導致的(註銷是有效的狀態)。

當然,沒有必要處理無效的狀態,因爲它永遠不會發生,即使是瞬間的。

+0

我用我的減速器代碼編輯了我的問題。看起來沒問題嗎? – philk

相關問題