与 useSelector 混淆

问题描述

所以我想使用 connect 中的 react-redux 函数访问状态(使用 redux 进行状态管理)。

connect(mapStatetoProps)(MyComponent)

但是当我尝试访问状态值时,它返回 undefined。

然后,我所做的唯一更改是删除 connect 并使用 useSelector 钩子引入我的组件,它运行良好。

直到现在,我一直认为它们是相同的(在提供对状态的访问方面),但它的工作方式完全不同。

这是代码(我认为在这个问题的上下文中没有用,但也许我错了);

使用 useSelector

const UnRegisteredStack = (props) => {
    const { token,verified } = useSelector((state) => ({
        token: state.token,verified: state.verified,}));
    return (
        <NavigationContainer>
            {token == null ? (
                <unRegistered.Navigator
                    initialRouteName="login"
                    screenoptions={{ headerShown: false }}
                >
                    <unRegistered.Screen name="login" component={Login} />
                    <unRegistered.Screen name="register" component={Register} />
                    <unRegistered.Screen name="passwordreset" component={PasswordReset} />
                </unRegistered.Navigator>
            ) : (
                <unRegistered.Navigator
                    initialRouteName="verifyemail"
                    screenoptions={{ headerShown: false }}
                >
                    {verified == null ? (
                        <unRegistered.Screen name="verifyemail" component={VerifyEmail} />
                    ) : (
                        <unRegistered.Screen name="details" component={Details} />
                    )}
                </unRegistered.Navigator>
            )}
        </NavigationContainer>
    );
};

使用 connect

const UnRegisteredStack = (props) => {
    const { token,verified } = props;
    return (
        <NavigationContainer>
            {token == null ? (
                <unRegistered.Navigator
                    initialRouteName="login"
                    screenoptions={{ headerShown: false }}
                >
                    <unRegistered.Screen name="login" component={Login} />
                    <unRegistered.Screen name="register" component={Register} />
                    <unRegistered.Screen name="passwordreset" component={PasswordReset} />
                </unRegistered.Navigator>
            ) : (
                <unRegistered.Navigator
                    initialRouteName="verifyemail"
                    screenoptions={{ headerShown: false }}
                >
                    {verified == null ? (
                        <unRegistered.Screen name="verifyemail" component={VerifyEmail} />
                    ) : (
                        <unRegistered.Screen name="details" component={Details} />
                    )}
                </unRegistered.Navigator>
            )}
        </NavigationContainer>
    );
};

const mapStatetoProps = (state) => ({
   token: state.token,verified: state.verified

})

connect(mapStatetoProps)(UnRegisteredStack)

 

解决方法

文档中省略的一个区别是,使用 useSelector 的组件使用了较新的 React 钩子哲学,然后可以使用自身而无需单独的包装器组件,而 connect(...)(UnRegisteredStack) 正在使用通过将组件包装在包装器中来增加组件的旧哲学,例如:

const UnRegisteredStackHooks = (props) => {
    const { token,verified } = useSelector((state) => ({
        token: state.token,verified: state.verified,}));
    // rest of component
}

const UnRegisteredStackUnconnected = (props) => {
    // rest of component
}
const UnRegisteredStackConnected = connect(mapStateToProps)(UnRegisteredStackUnconnected);

const App = () => (
   <Provider store={store}>
      {/* Works ok */}
      <UnRegisteredStackHooks /> 
      {/* Needs the props passed */}
      <UnRegisteredStackUnconnected token={store.getState().token} />
      {/* Works ok */}
      <UnRegisteredStackConnected />
   </Provider>

);

这两种方法各有优缺点。使用 connect,您可以选择拥有一个无需与 redux 耦合即可工作的组件,因为您始终可以在没有 connect 的情况下导出组件并在其他地方引入 connect。如果您不想创建模拟商店,这在测试时特别有用。

另一方面,钩子使定义组件变得更加简单,如果需要测试,您可以随时模拟钩子。