【发布时间】:2021-05-28 22:06:45
【问题描述】:
我正在开发一个带有 expo 的 react-native 应用程序。
我的组件之间需要一些共享存储,所以我转向了 redux。
但是,经过几个小时的努力,我无法让它工作:我不断收到臭名昭著的错误“错误:在“连接(AppProvider)”的上下文中找不到“商店”。
但是,我觉得一切都很好。我不明白错误来自哪里。有谁知道我做错了什么?
这是我的 index.js 文件:
import React from 'react'
import { Provider } from 'react-redux'
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux'
import App from './App.js'
import store from './store/store.js'
import { setNCServer, setToken } from './store/actions';
import { registerRootComponent } from 'expo';
const AppProvider = () => {
return (
<Provider store={store}>
<App />
</Provider>
)
}
// Initialise store
const mapDispatchToProps = dispatch => (
bindActionCreators({
setNCServer,
setToken,
}, dispatch)
);
const mapStateToProps = (state) => {
return state
};
const connector = connect(mapStateToProps, mapDispatchToProps)
const AppRoot = connector(AppProvider);
export default registerRootComponent(AppRoot);
这是我的 store.js 文件:
import { createStore } from 'redux';
import CombinedReducers from './reducers.js';
const store = createStore(CombinedReducers);
export default store
这是我的 reducers.js 文件:
import { combineReducers } from 'redux';
const tokenReducer = (state = null, action) => {
switch (action.type) {
case 'set':
return action.payload;
default:
return state
}
};
const NCServerReducer = (state = null, action) => {
switch (action.type) {
case 'set':
return action.payload;
default:
return state
}
};
export default combinedReducers({
NCServer: NCServerReducer,
token: tokenReducer
});
这是我的 action.js 文件:
export const setNCServer = NCServer => (
{
type: 'set',
payload: NCServer,
}
);
export const setToken = token => (
{
type: 'set',
payload: token,
}
);
======== 更新 =========
根据 Pera 的回答 (https://stackoverflow.com/a/67746329/16063826),我尝试将我的 connect 逻辑移动到 App 组件中。
不太确定该怎么做,我的index.js 文件现在看起来像这样:
import React from 'react';
import { Provider } from 'react-redux' ;
import App from './App.js';
import store from './store/store.js';
export default class AppProvider extends React.Component {
render() {
return (
<Provider store={store}>
<App />
</Provider>
)
}
}
还有我的App.js 文件,像这样:
import React from 'react';
// Persistent storage
import AsyncStorage from '@react-native-async-storage/async-storage';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux'
import { setNCServer, setToken } from './store/actions';
import { registerRootComponent } from 'expo';
// 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';
// 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 (
<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>
)
}
}
}
// Initialise store
const mapDispatchToProps = dispatch => (
bindActionCreators({
setNCServer,
setToken,
}, dispatch)
);
const mapStateToProps = (state) => {
return state
};
const connector = connect(mapStateToProps, mapDispatchToProps)
const AppRoot = connector(App);
export default registerRootComponent(AppRoot);
但我仍然遇到同样的错误。
错误日志对我来说有点奇怪:
Info Before connect
13:04
Info After connect
13:04
Info before createStore CombinedReducers: [Function combination]
13:04
Info after createStore
13:04
Info Running application on Mon iPhone.
13:04
Error Error: Could not find "store" in the context of "Connect(App)". 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(App) in connect options.
13:04
This error is located at:
in Connect(App) (created by ExpoRoot)
in ExpoRoot (at renderApplication.js:45)
in RCTView (at View.js:34)
in View (at AppContainer.js:106)
in DevAppContainer (at AppContainer.js:121)
in RCTView (at View.js:34)
in View (at AppContainer.js:132)
in AppContainer (at renderApplication.js:39)
所以,当我启动应用程序时,它会遍历 connect 和 createStore 函数,然后在 ExpoRoot 中失败...。这里可能出了什么问题?
【问题讨论】:
标签: react-native redux expo