2016-07-07 49 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

相关问题