【问题标题】:Could not find "store" in the context of "Connect(HomeScreen)". Either wrap the root component in a... or pass a custom React context provider在“Connect(HomeScreen)”的上下文中找不到“store”。将根组件包装在...中或传递自定义的 React 上下文提供程序
【发布时间】:2021-06-16 15:54:21
【问题描述】:

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

我们正在使用

重写我们的身份验证层
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

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

【问题讨论】:

    标签: react-native redux react-redux


    【解决方案1】:

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

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

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

    【讨论】:

    • 嗯,整个目标是获取用户令牌以在进入时呈现正确的视图。我一直在关注reactnavigation.org/docs/auth-flow。但是因为我使用 redux 来管理状态,所以指南说我应该共享上下文以实现我的身份验证流程目标。你会推荐什么?
    • 当然,您可以使用上下文来传递身份验证数据,但您不应覆盖 React-Redux 的配​​置以使用该上下文实例。这就像你打开一封寄给 React-Redux 的邮件,用购物清单替换整封信,把它放回邮箱,然后想知道“为什么它不知道原信说了什么?”。只需删除为 React-Redux API 定义 context 参数的所有位。
    • 这是我最初的尝试,但我无法使令牌字段与两个不同的上下文保持同步。您对使用 redux 实现身份验证流程的最佳方法有任何说明吗?
    • 阅读后不确定你的类比是否正确 - react-redux.js.org/using-react-redux/… 声明我们可以使用我们自己定义的上下文。因此,创建自定义并在应用程序之间共享应该不是问题
    • 没有。您完全误解了“自定义上下文”功能的目的。这适用于极其罕见的用例,例如应用程序的不同部分使用多个 Redux 存储。您正在尝试将两个完全不同的上下文混合在一起,覆盖 React-Redux 的行为,这会破坏您的应用程序。 请不要这样做。你根本不应该弄乱 React-Redux 的上下文。只需创建您的身份验证上下文,渲染它并传入一个值,然后在您自己的组件中读取该上下文。就是这样。
    【解决方案2】:

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

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

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

    您可以使用自定义挂钩处理已有的上下文。您可以创建一个使用const { signIn } = useAuth() 的设置,而不是像示例中那样使用const { signIn } = React.useContext(AuthContext)。你的 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 &lt;Provider&gt;:

    function App() {
      const { signIn } = useAuth();
    
      const [username, setUsername] = React.useState('');
    
      return (
        <Button onPress={() => signIn(username)}>Sign In</Button>
      )
    }
    

    【讨论】:

      猜你喜欢
      • 2021-10-19
      • 1970-01-01
      • 2021-10-28
      • 1970-01-01
      • 2019-11-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-19
      相关资源
      最近更新 更多