在“Connect(HomeScreen)”的上下文中找不到“store”。要么将根组件包装在...中,要么传递自定义 React 上下文提供程序

时间:2021-06-16 15:54:21

标签: react-native redux react-redux

检查已经问过的许多问题,但仍然无法弄清楚这一点。

我们正在使用

重写我们的身份验证层
export default AuthContext = React.createContext();

并将其包裹在我们的 AppNavigator 中

function AppNavigator(props) {
  const [state, dispatch] = useReducer(accountReducer, INITIAL_STATE);
  const authContext = React.useMemo(
    () => ({
      loadUser: async () => {
        const token = await keychainStorage.getItem("token");

        if (token) {
          await dispatch({ type: SIGN_IN_SUCCESS, token: token });
        }
  },

  signIn: async (data) => {
    client
      .post(LOGIN_CUSTOMER_RESOURCE, data)
      .then((res) => {
        const token = res.data.accessToken;
        keychainStorage.setItem("token", token);

        dispatch({ type: SIGN_IN_SUCCESS, token: token });
      })
      .catch((x) => {
        dispatch({ type: SIGN_IN_FAIL  });
      });
  },

  signOut: () => {
    client.delete({
          LOGOUT_CUSTOMER_RESOURCE
        });

        dispatch({ type: SIGN_OUT_SUCCESS });
      }
    }),
    []
  );
  console.log("token start", state.token);
  return (
    <AuthContext.Provider value={authContext}>
      <NavigationContainer
        theme={MyTheme}
        ref={(navigatorRef) => {
          NavigationService.setTopLevelNavigator(navigatorRef);
        }}
        onStateChange={(state) => {
          NavigationService.setAnalytics(state);
        }}
      >
        <AppStack.Navigator initialRouteName="App" screenOptions={hideHeader}>
          {state.token != null ? (
            <AppStack.Screen name="App" component={AuthMainTabNavigator} />
          ) : (
            <>
              <AppStack.Screen name="App" component={MainTabNavigator} />
              <AppStack.Screen name="Auth" component={AuthNavigator} />
            </>
          )}
        </AppStack.Navigator>
      </NavigationContainer>
    </AuthContext.Provider>
  );
}

export default AppNavigator;

App.js - 渲染功能

 <Root>
      <StoreProvider store={store} context={AuthContext}>
        <PersistGate loading={null} persistor={persistor}>
          <SafeAreaProvider>
                <AppNavigator  context={AuthContext}/>
          </SafeAreaProvider>
        </PersistGate>
      </StoreProvider>
    </Root>

HomeScreen.js

export default connect(mapStateToProps, mapDispatchToProps, null, { context: AuthContext })(HomeScreen);

还是收到了

Error: Could not find "store" in the context of "Connect(HomeScreen)". Either wrap the root component in a <Provider>, or pass a custom React context provider to <Provider> and the corresponding React context consumer to Connect(HomeScreen) in connect options.

我们已经阅读了 REDUX 文档:

https://react-redux.js.org/using-react-redux/accessing-store#using-the-usestore-hook

根本无法弄清楚为什么我们会收到此错误。

2 个答案:

答案 0 :(得分:2)

我不确定您要在这里完成什么,但这是非常错误的:

export default connect(mapStateToProps, mapDispatchToProps, null, { context: AuthContext })(HomeScreen);

看起来你把两种不同的东西混在一起了。您正在尝试创建一个用于您自己的身份验证状态的上下文,但您也在尝试使用相同的上下文实例来覆盖 React-Redux 自己的默认上下文实例。 不要那样做!你不应该将自定义上下文实例传递给connect<Provider>,除非非常 > 罕见情况。

答案 1 :(得分:0)

只有在与@markerikson 的评论中通读您的讨论后,我才明白您想要实现的目标。

React Navigation 文档中的 example 创建了一个上下文 AuthContext,以便让 auth 函数对其后代可用。它需要这样做,因为 statedispatch 来自 React.useReducer 钩子,所以它们只存在于组件的范围内。

您的设置有所不同,因为您使用的是 Redux。您的 statedispatch 已经通过 React-Redux 上下文提供程序可用于您的组件,并且可以通过 connectuseSelectoruseDispatch您不需要额外的上下文来存储您的身份验证信息。

您可以使用自定义挂钩处理已有的上下文。您可以创建一个使用 const { signIn } = React.useContext(AuthContext) 的设置,而不是像示例中那样使用 const { signIn } = useAuth()。您的 useAuth 钩子可以通过在内部使用 React-Redux 钩子来访问您的 Redux 存储。

这是一个钩子代码:

import * as React from 'react';
import * as SecureStore from 'expo-secure-store';
import { useDispatch } from "react-redux";

export const useAuth = () => {
  
  // access dispatch from react-redux
  const dispatch = useDispatch();

  React.useEffect(() => {
      // same as in example
  }, []);

  // this is the same as the example too
  const authContext = useMemo(
    () => ({
      signIn: async data => {
        dispatch({ type: 'SIGN_IN', token: 'dummy-auth-token' });
      },
      signOut: () => dispatch({ type: 'SIGN_OUT' }),
      signUp: async data => {
        dispatch({ type: 'SIGN_IN', token: 'dummy-auth-token' });
      },
    }),
    []
  );

  // but instead of passing that `authContext` object to a `Provider`, just return it!
  return authContext;
}

在你的组件中,它必须在你的 React-Redux <Provider> 中:

function App() {
  const { signIn } = useAuth();

  const [username, setUsername] = React.useState('');

  return (
    <Button onPress={() => signIn(username)}>Sign In</Button>
  )
}