reactjs - 使用带有 react-navigation 的 redux 存储
问题描述
我正在尝试使用 expo 在我的 react-native 应用程序中添加一个 redux 商店。
该应用程序如下所示:
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
在Redux组件内部Provider
的组件上使用。现在你Provider
在里面,App
所以你不能使用connect
on App
。你需要Provider
向上移动一个级别。
我在这里也看到了许多其他问题:this.props.state.setToken(token)
应该是this.props.setToken(token)
并且this.state.token
应该是this.props.state.token
——但实际上你应该使用它mapStateToProps
来选择令牌而不是返回整个状态!
你可能会发现useSelector
anduseDispatch
钩子更直观。
url.url
名称非常混乱。真的这是一个带有属性的事件,url
所以你应该调用它e
或event
. 但是您也可以将其解构为({url})
代替(e)
and 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>
);
}
推荐阅读
- r - R - 我如何最有效地滞后/领先 data.table 中的多个列多个时期
- javascript - 为什么我的 javascript 代码没有从 html 更新任何文本?
- java - 如何在 JsonArray 中创建(键,值)
- node.js - 如何使用 electron-builder 打包预编译的二进制文件
- c++ - 如何限制整数增加的数量?C++
- postman - Postman 可视化:我可以创建条件语句吗?
- python - 仅返回两个数据框列中的异常的最简单方法是什么?
- python - Google Drive API 看不到共享文件夹中的文件
- python - 如何将值列表转换为列表中的索引/切片?
- c# - dotnet core Google Cloud Function 与 Firebase Admin SDK