我有这个Protected
HOC。其目的是仅在用户通过身份验证时呈现其WrappedComponent
。否则应该呈现AuthenticateComponent
(通常是登录组件)。
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
,因此有效。
我想知道那可能是什么样的种族情况?
答案 0 :(得分:1)
我不知道如果没有看到代码,但看起来你的reducer会改变状态。减速器不应该改变状态。它应该改为创建一个具有正确属性的新状态。
这一点的全部意义在于防止竞争条件和其他异常现象。
React Redux经过精心设计,可以防止您在此处看到的各种问题。它确实要求你遵守Redux规则。主要的一点是,reducer 必须是纯函数。
如果您的reducer修改旧状态并返回它,则Redux没有简单的方法可以看到您对状态进行了修改。事实上,它将假设没有做出任何改变。因此,没有任何东西会被重新渲染。
修改强>
你的减速机看起来很好,即使我看不到account
减速器在其他地方是如何使用的,我认为它也很好。
我认为问题在于,您的组件实际上没有渲染,但渲染方法仍然在LOGOUT
上调用。发生的事情是,如果该子组件要求这样的渲染,React将很乐意渲染一个子组件。由于connect
挂钩到store
更新以实现这一点,所以这就是正在发生的事情。
当您的州发生变化时,connect
会通过调用props
重新评估WrappedComponent
mapStateToProps
,并且会发现这些道具已经更改(由于不再登录,因此这个数据与以前不同)。然后,Connect将指示React重新呈现WrappedComponent
。 React会这样做。反过来,您的render
方法可能会对传递的数据造成问题,因为它的无效数据仅在用户登录时使用。
解决方案是简单地使用虚拟<div/>
退出渲染。这个div,一个虚拟的DOM元素,实际上永远不会进入DOM。 React缓存元素并批量DOM更新。因此,在将它合并到DOM之前,React会删除整个WrappedComponent
,不幸的是,在它已经呈现新版本之后。
请注意,Redux与Connect结合使用确实是罪魁祸首,因为Redux没有组件概念,因此无法考虑它们,而Connect按照创建的顺序订阅商店,并且然后,store按照订阅的顺序通知组件。
最终订单取决于渲染顺序和安装顺序,许多组件在决定此顺序时起作用。它根本不稳定,因此不应该依赖它。
构建连接组件时,请务必编写mapStateToProps
以获取任何有效状态,并从目标组件的那些编译有效道具。无论是添加虚拟值,还是更改组件本身以使传递给它的任何内容都有效,重要的是允许所有有效状态解析为有效道具,即使这些道具所用的组件从未打算显示。通过这种方式,您可以防止由于无效道具导致的错误,这些道具实际上是由有效状态导致的(被注销的是有效状态)。
当然,没有必要处理无效状态,因为它永远不会发生,即使是瞬间也不会发生。