【问题标题】:Using a redux store with react-navigation使用带有 react-navigation 的 redux 存储
【发布时间】:2021-05-29 17:57:03
【问题描述】:

我正在尝试使用 expo 将 redux 商店添加到我的 react-native 应用程序中。

应用程序如下所示:

import React from 'react';

// Persistent storage
import AsyncStorage from '@react-native-async-storage/async-storage';

// Navigation
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import Login from './Login';
import Home from './Home';
import BoardScreen from './BoardScreen';
import BoardDetailsScreen from './BoardDetailsScreen';
import CardDetailsScreen from './CardDetailsScreen';

// Store
import { Provider } from 'react-redux';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import store from './store/store';
import { setNCServer, setToken } from './store/actions';


// For creating an URL handler to retrieve the device token
import * as Linking from 'expo-linking';

// Create Stack navigator
const Stack = createStackNavigator()

// Application
class App extends React.Component {

  constructor(props) {
    super(props)
    
    // Retrieve token from storage if available
    AsyncStorage.getItem('token').then(token => {
      this.props.state.setToken(token)  
    })

    // Register handler to catch Nextcloud's redirect after successfull login
    Linking.addEventListener('url', (url) => {this.handleRedirect(url)})
  }

  // Function to retrieve the device's token and save it after user logged in
  handleRedirect = async (url) => {
    if (url.url.startsWith('nc://login/server')) {
      try {
        token = url.url.substring(url.url.lastIndexOf(':'))
        console.log('Persisting token', token)
        AsyncStorage.setItem('token', token);  
        this.props.state.setToken(token)
      } catch (e) {
        // TODO
      } 
    }
  }

  render() {
    if (this.state.token === null) {
      // No token is stored yet, we need to get one
      return (
        <Provider store={store}>
          <NavigationContainer>
            <Stack.Navigator>
              <Stack.Screen name="Home" component={Home} />
              <Stack.Screen name="Login" component={Login} />
            </Stack.Navigator>
          </NavigationContainer>
        </Provider>
      ) 
    } else {
      return (
        <Provider store={store}>
          <NavigationContainer>
            <Stack.Navigator>
              <Stack.Screen name="AllBoard" component={BoardScreen} options={{title: 'All boards'}} />
              <Stack.Screen name="BoardDetails" component={BoardDetailsScreen} options={{title: 'Board details'}} />
              <Stack.Screen name="CardDetails" component={CardDetailsScreen} options={{title: 'Card details'}} />
            </Stack.Navigator>
          </NavigationContainer>
        </Provider>
      )
    }
  }
}

// Initialise store
const mapDispatchToProps = dispatch => (
  bindActionCreators({
    setNCServer,
    setToken,
  }, dispatch)
);
const mapStateToProps = (state) => {
  return state
};
const connector = connect(mapStateToProps, mapDispatchToProps)
export default connector(App);

问题:当我启动应用程序时,我收到了臭名昭著的错误“错误:在“Connect(App)”的上下文中找不到“store”。

我在这个问题上绞尽脑汁了好几个小时,却找不到我做错了什么。

谁能帮帮我?

【问题讨论】:

    标签: reactjs react-native redux expo react-navigation


    【解决方案1】:

    您只能在 Redux Provider 组件内部的组件上使用connect。现在你的ProviderApp 里面,所以你不能在App 上使用connect。您需要将Provider 上一级。

    我在这里也看到了许多其他问题:this.props.state.setToken(token) 应该是 this.props.setToken(token)this.state.token 应该是 this.props.state.token - 但实际上你应该使用 mapStateToProps 来选择令牌和不返回整个状态!

    您可能会发现 useSelectoruseDispatch 挂钩更直观。

    url.url 的命名非常混乱。真的,这是一个带有url 属性的事件,所以你应该称它为eevent。但您也可以将其解构为({url}) 而不是(e)e.url

    // Application contents
    class AppNavigation extends React.Component {
      constructor(props) {
        super(props);
    
        // Retrieve token from storage if available
        AsyncStorage.getItem('token').then((token) => {
          this.props.setToken(token);
        });
    
        // Register handler to catch Nextcloud's redirect after successfull login
        Linking.addEventListener('url', this.handleRedirect);
      }
    
      // Function to retrieve the device's token and save it after user logged in
      handleRedirect = async ({ url }) => {
        if (url.startsWith('nc://login/server')) {
          try {
            const token = url.substring(url.lastIndexOf(':'));
            console.log('Persisting token', token);
            AsyncStorage.setItem('token', token);
            this.props.setToken(token);
          } catch (e) {
            // TODO
          }
        }
      };
    
      render() {
        if (this.props.token === null) {
          // No token is stored yet, we need to get one
          return (
              <NavigationContainer>
                <Stack.Navigator>
                  <Stack.Screen name="Home" component={Home} />
                  <Stack.Screen name="Login" component={Login} />
                </Stack.Navigator>
              </NavigationContainer>
          );
        } else {
          return (
              <NavigationContainer>
                <Stack.Navigator>
                  <Stack.Screen
                    name="AllBoard"
                    component={BoardScreen}
                    options={{ title: 'All boards' }}
                  />
                  <Stack.Screen
                    name="BoardDetails"
                    component={BoardDetailsScreen}
                    options={{ title: 'Board details' }}
                  />
                  <Stack.Screen
                    name="CardDetails"
                    component={CardDetailsScreen}
                    options={{ title: 'Card details' }}
                  />
                </Stack.Navigator>
              </NavigationContainer>
          );
        }
      }
    }
    
    // Can just be an object of functions to bind - creates props `setNCServer` and `setToken`
    const mapDispatchToProps = {
      setNCServer,
      setToken,
    };
    
    // Creates a prop `token` with the token from state
    const mapStateToProps = (state) => {
      return {
        token: state.token,
      };
    };
    
    const connector = connect(mapStateToProps, mapDispatchToProps);
    
    const ConnectedNavigation = connector(AppNavigation);
    
    // use the connected component inside a redux Provider
    export default function App() {
      return (
        <Provider store={store}>
          <ConnectedNavigation />
        </Provider>
      );
    }
    

    【讨论】:

    • 嗨,我在 24 小时前就知道了。无论如何,感谢您的回答和评论:关于 react-native,我还有很多东西要学习 ;-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-08-02
    • 1970-01-01
    • 2022-01-17
    • 1970-01-01
    • 1970-01-01
    • 2018-03-06
    • 1970-01-01
    相关资源
    最近更新 更多