React Native header clickable with asyncStorage - javascript

Essentially, I have a Cloud Icon in the upper right hand corner of my app screen that when I click it I want it to edit an AsyncStorage variable in my application. And I am trying to get that variable to change the style of the <Icon> class.
To do this, I am trying to make it be a clickable element but I don't know how to transfer this onClick to a variable that each screen file sees.
Right now, the icon style ie based on navigation.state.params.cloud but that is only established on ComponentDidMount() in the each screen file.
Does anyone have any suggestions on how to accomplish this?
My React-Native app is set up like so:
index.js
import { AppRegistry } from 'react-native';
import App from './app/config/app';
AppRegistry.registerComponent('MobApp', () => App);
/config/app.js
import React from 'react';
import { TouchableOpacity, ActivityIndicator, AsyncStorage, Button, StatusBar, StyleSheet, View, Text, Image } from 'react-native';
import { StackNavigator, SwitchNavigator } from 'react-navigation'; // Version can be specified in package.json
import { configureFontAwesomePro } from "react-native-fontawesome-pro";
import Icon from "react-native-fontawesome-pro";
configureFontAwesomePro();
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
import AuthLoadingScreen from '../screens/AuthLoadingScreen';
import MainScreen from '../screens/main';
import SettingsScreen from '../screens/settings';
const cloudLogo = async function() {
let cloud = await AsyncStorage.getItem('cloud');
cloud = cloud === 'true';
cloud = !cloud;
await AsyncStorage.setItem('cloud', cloud.toString())
return cloud;
}
var navo = ({ navigation }) => {
return {
headerStyle: { backgroundColor:"#fff"},
headerTitle: (<View style={{flex: 1, flexDirection: 'row', justifyContent: 'center' }}><Image style={{ width:25, height: 25, marginTop: 3, marginRight: 5}} source={require('../images/logo.png')}/><Text style={{ color:"#3F61E7", fontSize: 26, fontWeight:"600" }}>MyCompany</Text></View>),
headerRight: (<TouchableOpacity activeOpacity={0.8} onPress={ async () => {
let cloud = await AsyncStorage.getItem('cloud');
cloud = cloud === 'true';
cloud = !cloud;
await AsyncStorage.setItem('cloud', cloud.toString())
console.log((await syncUtil.getLocal()).cloud)
} } style={{ marginRight:15 }}>
<Icon name="cloud" type={ typeof navigation.state.params == 'undefined' ? "solid" : (navigation.state.params.cloud ? "solid" : "light") } color="#3F61E7" size={30} />
</TouchableOpacity>)
}
}
const AppStack = StackNavigator({
Home: { screen: MainScreen, navigationOptions: navo },
Settings: { screen: SettingsScreen, navigationOptions: navo },
});
export default SwitchNavigator(
{
AuthLoading: AuthLoadingScreen,
App: AppStack
},
{
initialRouteName: 'AuthLoading',
}
);

Related

React-Native how to get ID from SVG

i am new in react-native and i am trying to programm an Android app there I have the following problem, I have a svg thats shows all states from germany and I want to get the ID of a state if I press on it.
my code
import React, { useState } from 'react';
import { StyleSheet, View, Text, TouchableOpacity } from 'react-native'
import Germany from '../assets/Karte_Bundesrepublik_Deutschland.svg'
const StatesScreen = () => {
const handlePress = (stateName) => {
console.log(stateName.id)
};
return (
<View style={styles.container}>
<Germany onPress={(e) => handlePress(e)} />
</View>
);
};
export default StatesScreen
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
});
Link to the svg:
https://upload.wikimedia.org/wikipedia/commons/2/2c/Karte_Bundesrepublik_Deutschland.svg

Is there a way to navigate to a different screen from the menu built in my Parent Component?

I am trying to add a simple customized navigation menu to my react-native app, but the issue that I am coming across right now is that I can't seem to find a way to navigate to the selected menu items corresponding screen. I tried the normal this.props.navigation.navigate('Home'), but it seems that there is no navigation prop, which makes sense because in my app I am assuming that the prop for navigation is passed down to the screens from my app.js through the use of <AppContainer />.
I have tried using the MainNavigator object in my App.js but it doesn't seem to be working and doesn't have a navigate function or anything like that.
I have also tried changing the structure of my render function in App.js a little bit but it still does not seem to be having much of an effect.
This is my App.js
import React, { Component } from 'react';
import {
View,
Text,
TouchableOpacity
} from 'react-native';
import {
createStackNavigator,
createAppContainer } from 'react-navigation';
// SCREEN
import MainScreen from './screens/MainScreen';
import CostAnalysis from './screens/CostAnalysis';
import DriverLog from './screens/DriverLog';
// SIDE MENU
import SideMenu from 'react-native-side-menu';
// REDUX IMPORTS
import { createStore, combineReducers } from 'redux';
import { Provider } from 'react-redux';
import { recordReducer } from './reducers/recordReducer';
import { databaseReducer } from './reducers/databaseReducer';
const MainNavigator = createStackNavigator({
Home: {screen: MainScreen},
DriverLog: {screen: DriverLog},
CostAnalysis: {screen: CostAnalysis},
}, {
defaultNavigationOptions: {
header: null
}
});
const AppContainer = createAppContainer(MainNavigator);
const rootReducer = combineReducers(
{records: recordReducer,
database: databaseReducer});
const store = createStore(rootReducer);
class App extends Component {
render() {
const menu = (<View style={{
backgroundColor: '#f0f0f0',
alignContent: 'center',
textAlign: 'center', height: '100%', width: '100%', paddingTop: '40%'}}>
<Text style={styles.menuTitle}>{'S K I P\nD R I V E R\nL O G'}</Text>
<TouchableOpacity onPress={() => {this.props.navigation.navigate('Home')}}>
<Text style={styles.menuItem}>HOME</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => {MainNavigator.navigate('DriverLog')}}>
<Text style={styles.menuItem}>DRIVING LOG</Text>
</TouchableOpacity>
</View>);
return (
<SideMenu menu={menu} >
<Provider store={store}>
<AppContainer />
</Provider>
</SideMenu>
);
}
}
const styles = {
menuTitle: {
marginBottom: 60,
fontSize: 40,
textAlign: 'center',
color: '#e74c3c'
},
menuItem: {
marginBottom: 10,
fontSize: 26,
textAlign: 'center'
}
}
export default (App);
Ideally I don't have to re-structure my entire app as I have made a lot of progress in other areas, but I would really like the menu to simply link to the correct places.
I'm still very new to react-native so I really don't know what else to try. If anyone can give me a hand it would be greatly appreciated!
Thanks :)
PS: See a picture of the menu to illustrate what I mean
Menu Screenshot
you have to implement the constructor
class App extends Component {
constructor(props) {
super(props);
}
}
or
if you are using a drawer use it as a separate component
import React, { Component } from 'react';
import {
View,
Text,
TouchableOpacity
} from 'react-native';
class SideDrawer extends Component{
constructor(props) {
super(props);
}
render(){
return(
<View style={{
backgroundColor: '#f0f0f0',
alignContent: 'center',
textAlign: 'center', height: '100%', width: '100%', paddingTop: '40%'}}>
<Text style={styles.menuTitle}>{'S K I P\nD R I V E R\nL O G'}</Text>
<TouchableOpacity onPress={() => {this.props.navigation.navigate('Home')}}>
<Text style={styles.menuItem}>HOME</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => {MainNavigator.navigate('DriverLog')}}>
<Text style={styles.menuItem}>DRIVING LOG</Text>
</TouchableOpacity>
</View>
)
}
}
export default sideDrawer
then in your navigator
const HomeNavigator = StackNavigator(
Home: {screen: MainScreen},
DriverLog: {screen: DriverLog},
CostAnalysis: {screen: CostAnalysis},
}
const MainNavigator = DrawerNavigator({
Home: {
screen: HomeNavigator,
},
}, {
contentComponent: sideDrawer,
drawerWidth: width * .7,
drawerOpenRoute: 'DrawerOpen',
drawerCloseRoute: 'DrawerClose',
drawerToggleRoute: 'DrawerToggle',
});

How to change screens with react-navigation (using a button)

I'm new to react native, but I've been researching how to redirect to new activities with buttons for the last few hours with no avail. My current solution involves me using react-navigation from multiple files, with App.js creating the StackNavigator for the rest of the pages. However, whenever I press the button on Initial.js, nothing happens.
I followed Damien Manson's tutorial on Invariant Violation: The navigation prop is missing for this navigator, but the button still doesn't work. I tried referencing App before calling my button, but whenever I try to run it on the emulator, it doesn't show me an error log and it never loads. It stays at "Downloading JavaScript bundle: 100%" for minutes until the emulator itself crashes.
Here's my App.js
import Initial from './components/Initial'
import Statistics from './components/Statistics'
const RootStack = createStackNavigator({
Default: {
screen: Initial
},
Stats: {
screen: Statistics
}
});
const App = createAppContainer(RootStack);
export default App;
Here's my Initial.js
import { StyleSheet, ImageBackground, Image, View, Text, Button } from 'react-native';
import { Font } from 'expo';
import App from '../App';
import {withNavigation} from 'react-navigation';
import Statistics from './Statistics';
export default class Initial extends React.Component {
static navigationOptions = {header: null}
componentDidMount() {
Font.loadAsync({'pt': require('../assets/fonts/pt.ttf')});
Font.loadAsync({'Karla': require('../assets/fonts/Karla-Regular.ttf')});
Font.loadAsync({'Space-Mono': require('../assets/fonts/SpaceMono-Regular.ttf')});
}
state = { fontLoaded: false};
async componentDidMount() {
await Font.loadAsync({'pt': require('../assets/fonts/pt.ttf'),});
await Font.loadAsync({'Karla': require('../assets/fonts/Karla-Regular.ttf'),});
await Font.loadAsync({'Space-Mono': require('../assets/fonts/SpaceMono-Regular.ttf'),});
this.setState({fontLoaded: true});
}
render() {
return (
<ImageBackground
source = {require('../assets/blue-bin.jpg')}
style = {styles.container}>
<View style = {styles.parentView}>
{this.state.fontLoaded ? (<Text style={styles.logoText}>!arbitrary</Text>) : null}
<Image source = {require('../assets/sadparrot.gif')} style = {styles.logo}/>
<Text style = {styles.textBox}>With its easily navigatible interface, the Chicago-based app, !arbitrary, aims to educate the masses about recyclable items, while emphasizing the importance of being sustainable.</Text>
<View style = {styles.redirect}>
<Button
title="Start"
onPress={() => this.props.navigation.navigate('Statistics')}
/>
</View>
</View>
</ImageBackground>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
width: '100%',
height: '100%',
},
parentView: {
flex: 1,
flexDirection: 'column',
backgroundColor: 'rgba(5,9,12, 0.6)',
justifyContent: 'center',
alignItems: 'center'
},
logoText: {
color: '#fff',
fontSize: 36,
fontFamily: 'pt'
},
textBox: {
width: 200,
height: 175,
fontFamily: 'sans-serif',
fontSize: 14,
color: '#fff',
borderColor: '#fff',
borderWidth: 2,
justifyContent: 'center',
marginTop: 50,
padding: 20
},
logo: {
width: 200,
height: 200
},
redirect: {
width: 80,
height: 30,
marginTop: 30
},
statistics: {
flex: 1,
width: '100%',
height: '100%',
backgroundColor: '#1B384F'
},
bigText: {
color: '#fff',
fontSize: 20,
fontFamily: 'Space-Mono'
}
});
Here's my Statistics.js
import { StyleSheet, ImageBackground, Image, View, Text, Button } from 'react-native';
import { Font } from 'expo';
import {withNavigation} from 'react-navigation';
class Statistics extends React.Component {
render() {
return(
<Text>Avail!</Text>
);
}
}
export default withNavigation(Statistics);
NOTE: I omitted my StyleSheet in Initial.js for the sake of being concise.
You need to navigate to your screen name which is Stats.
<Button
title="Start"
onPress={() => this.props.navigation.navigate('Stats')}/>
I had the same issue. I fixed is by using withNavigation
In Statistics class,
1st, Import withNavigation.
import { withNavigation } from 'react-navigation';
Then, export Statistics class as below.
export default withNavigation(Statistics)
Try this
const RootStack = createStackNavigator({
Default: {
screen: Initial
},
Stats: {
screen: props => <Statistics {...props} />
}
});

react-navigation drawer updating multiple times

I am building an application with React Native and React Navigation, I have made all the settings and it is working, however, when the drawer is fired the image is updated multiple times causing spikes and failures to trigger buttons contained in it.
e.g.:
I am using:
react: 16.8.3,
react-native: 0.59.1,
react-native-ui-kitten: ^3.1.2,
react-navigation: ^3.4.0
I was using version 3 of RN and to try to solve I went back to version 2 but without success.
I put some warnings in the method that executes the image and saw that it is called whenever there is this update.
I already changed the image in different sizes and formats but it also did not help.
I already tested on cell phones and emulators but with no success.
Drawer:
import React, { Component } from 'react';
import {
TouchableHighlight,
View,
ScrollView,
Image,
Platform,
StyleSheet,
} from 'react-native';
import {
RkStyleSheet,
RkText,
RkTheme,
} from 'react-native-ui-kitten';
import Icon from 'react-native-vector-icons/Ionicons';
import Routes from '../../config/navigation/routes';
import logo from '../../assets/smallLogo.png';
export default function SideNavigation(props) {
const onMenuItemPressed = item => {
props.navigation.navigate(item.id);
};
const renderIcon = () => (<Image style={styles.image} source={logo}/>);
const renderMenuItem = item => (
<TouchableHighlight style={styles.container} key={item.id} underlayColor={RkTheme.current.colors.button.underlay} activeOpacity={1} onPress={() => onMenuItemPressed(item)}>
<View style={styles.content}>
<View style={styles.content}>
<RkText style={styles.icon} rkType='moon primary xlarge'><Icon name={item.icon} size={25}/></RkText>
<RkText rkType='regular'>{item.title}</RkText>
</View>
{/*<RkText rkType='awesome secondaryColor small'>{FontAwesome.chevronRight}</RkText>*/}
</View>
</TouchableHighlight>
);
const renderMenu = () => Routes.map(renderMenuItem);
return (
<View style={styles.root}>
<ScrollView showsVerticalScrollIndicator={false}>
<View style={[styles.container, styles.content]}>
{renderIcon()}
</View>
{renderMenu()}
</ScrollView>
</View>
)
}
const styles = RkStyleSheet.create(theme => ({
container: {
height: 60,
paddingHorizontal: 16,
borderTopWidth: StyleSheet.hairlineWidth,
borderColor: theme.colors.border.base,
},
root: {
paddingTop: Platform.OS === 'ios' ? 20 : 0,
backgroundColor: theme.colors.screen.base
},
content: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
},
icon: {
marginRight: 13,
},
image:{
resizeMode: 'contain',
maxWidth: 125
}
}));
Drawer setup:
import React, {Component} from 'react';
import { View, Text} from 'react-native';
import Login from './screens/login';
import PasswordRecovery from './screens/passwordRecovery';
import Home from './screens/home';
import SideNavigator from './components/sideMenu';
import { bootstrap } from './config/bootstrap';
import {
createDrawerNavigator,
createStackNavigator,
createAppContainer
} from 'react-navigation';
import { withRkTheme } from 'react-native-ui-kitten';
import NavBar from './components/navBar';
import AppRoutes from './config/navigation/routesBuilder';
import Splash from './screens/splash';
bootstrap();
const renderHeader = (navigation, props) => {
const ThemedNavigationBar = withRkTheme(NavBar);
return (
<ThemedNavigationBar navigation={navigation} headerProps={props} />
);
};
const App = createStackNavigator({
Splash: Splash,
Login: Login,
PasswordRecovery: PasswordRecovery,
Main: createDrawerNavigator({
...AppRoutes
},{
contentComponent: props => {
const SideNav = withRkTheme(SideNavigator);
return <SideNav {...props}/>
}
}),
},
{
headerMode: 'none',
})
export default createAppContainer(App);
Routes setup:
import React from 'react';
import _ from 'lodash';
import { createStackNavigator } from 'react-navigation';
import { withRkTheme } from 'react-native-ui-kitten';
import transition from './transitions';
import Routes from './routes';
import NavBar from '../../components/navBar';
const main = {};
const flatRoutes = {};
const routeMapping = (route) => ({
screen: withRkTheme(route.screen),
title: route.title,
});
(Routes).forEach(route => {
flatRoutes[route.id] = routeMapping(route);
main[route.id] = routeMapping(route);
route.children.forEach(nestedRoute => {
flatRoutes[nestedRoute.id] = routeMapping(nestedRoute);
});
});
const renderHeader = (navigation, props) => {
const ThemedNavigationBar = withRkTheme(NavBar);
return (
<ThemedNavigationBar navigation={navigation} headerProps={props} />
);
};
const DrawerRoutes = Object.keys(main).reduce((routes, name) => {
const rawRoutes = routes;
rawRoutes[name] = {
name,
screen: createStackNavigator(flatRoutes, {
initialRouteName: name,
headerMode: 'screen',
cardStyle: { backgroundColor: 'transparent' },
transitionConfig: transition,
defaultNavigationOptions: ({ navigation }) => ({
gesturesEnabled: false,
header: (props) => renderHeader(navigation, props),
}),
}),
};
return rawRoutes;
}, {});
const AppRoutes = DrawerRoutes;

undefined is not an object (evaluating 'this.props.navigation')

I'm trying to create a React Native app with some basic routing.
This is my code so far:
App.js:
import React from 'react'
import { StackNavigator } from 'react-navigation'
import MainScreen from './classes/MainScreen'
const AppNavigator = StackNavigator(
{
Index: {
screen: MainScreen,
},
},
{
initialRouteName: 'Index',
headerMode: 'none'
}
);
export default () => <AppNavigator />
MainScreen.js:
import React, { Component } from 'react'
import { StyleSheet, Text, View, Button, TouchableOpacity, Image } from 'react-native'
import HomeButton from './HomeButton'
export default class MainScreen extends Component {
static navigatorOptions = {
title: 'MyApp'
}
constructor(props) {
super(props)
}
render() {
return (
<View style={styles.container}>
<Image source={require('../img/logo.png')} style={{marginBottom: 20}} />
<HomeButton text='Try me out' classType='first' />
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center'
}
})
HomeButton.js:
import React, { Component } from 'react'
import { StyleSheet, Text, View, Button, TouchableOpacity } from 'react-native'
import { StackNavigator } from 'react-navigation'
export default class HomeButton extends Component {
constructor(props) {
super(props)
}
render() {
return (
<TouchableOpacity
onPress={() => navigate('Home')}
style={[baseStyle.buttons, styles[this.props.classType].style]}
>
<Text style={baseStyle.buttonsText}>{this.props.text.toUpperCase()}</Text>
</TouchableOpacity>
)
}
}
var Dimensions = require('Dimensions')
var windowWidth = Dimensions.get('window').width;
const baseStyle = StyleSheet.create({
buttons: {
backgroundColor: '#ccc',
borderRadius: 2,
width: windowWidth * 0.8,
height: 50,
shadowOffset: {width: 0, height: 2 },
shadowOpacity: 0.26,
shadowRadius: 5,
shadowColor: '#000000',
marginTop: 5,
marginBottom: 5
},
buttonsText: {
fontSize: 20,
lineHeight: 50,
textAlign: 'center',
color: '#fff'
}
})
const styles = {
first: StyleSheet.create({
style: { backgroundColor: '#4caf50' }
})
}
Everything works fine, but when pressing the button I get
Can't find variable: navigate
I've read that I have to declare it like this:
const { navigate } = this.props.navigation
So I edited HomeButton.js and added that line at the beginning of the render function:
render() {
const { navigate } = this.props.navigation
return (
<TouchableOpacity
onPress={() => navigate('Home')}
style={[baseStyle.buttons, styles[this.props.classType].style]}
>
<Text style={baseStyle.buttonsText}>{this.props.text.toUpperCase()}</Text>
</TouchableOpacity>
)
}
Now I get:
TypeError: undefined is not an object (evaluating 'this.props.navigation.navigate')
It seems that the navigation object is not coming into the properties, but I don't understand where should I get it from.
What am I missing here?
React-navigation pass navigation prop to the screen components defined in the stack navigator.
So in your case, MainScreen can access this.props.navigation but HomeButton can't.
It should work if you pass navigation prop from MainScreen to HomeButton :
<HomeButton text='Try me out' classType='first' navigation={this.props.navigation}/>
Edit: You have to define the Homescreen in your stack navigator in order to navigate to it, your onPress={() => navigate('Home')} won't work until then.

Categories