Good evening everyone,
I created two screens and I would like to pass the context to one of this screen but it doesn't work.
Here what I have so far :
App :
import React from 'react';
import { createAppContainer } from "react-navigation";
import { createStackNavigator } from "react-navigation-stack";
import HomeScreen from "./src/screens/HomeScreen";
import ExpenseScreen from "./src/screens/ExpenseScreen";
import BalanceScreen from "./src/screens/BalanceScreen";
import {ExpenseProvider} from "./src/context/ExpenseContext";
const navigator = createStackNavigator(
{
Home:HomeScreen,
Expense:ExpenseScreen,
Balance: BalanceScreen
},
{
initialRouteName:"Home",
defaultNavigationOptions:{
title:"App",
}
}
)
const App = createAppContainer(navigator);
export default () => {
return <ExpenseProvider>
<App/>
</ExpenseProvider>
};
HomeScreen:
import React from "react";
import { Text, StyleSheet, View, Button} from "react-native";
const HomeScreen = ({navigation}) => {
return(
<View>
<Text style={styles.text}>HomeScreen</Text>
{/*Shows default display*/}
<Button
onPress={()=> navigation.navigate('Expense')}
title="Expense Tracker"
/>
<Button
onPress={()=> navigation.navigate('Balance')}
title="Balance"
/>
</View>
)
};
const styles = StyleSheet.create({
text: {
fontSize: 30
}
});
export default HomeScreen;
Provider :
import React from 'react';
const ExpenseContext = React.createContext();
export const ExpenseProvider = ({children}) => {
const expensePosts = [
{title: 'Expense Post #1'},
{title: 'Expense Post #2'},
{title: 'Expense Post #3'}
]
return <ExpenseContext.Provider value={expensePosts}>{children}</ExpenseContext.Provider>
};
export default ExpenseContext;
Screen :
import React, {useContext} from "react";
import { Text, StyleSheet, View, Button, Flatlist } from "react-native";
import ExpenseContext from '../context/ExpenseContext';
const ExpenseScreen = () => {
const expensePosts = useContext(ExpenseContext)
return(
<View>
<Text style={styles.text}>Expense Tracker</Text>
<Flatlist
data={expensePosts}
keyExtractor={(expensePost) => expensePost.title}
renderItem={({item}) => {
return <Text>{item.title}</Text>
}}
/>
</View>
)
};
const styles = StyleSheet.create({
text: {
fontSize: 30
}
});
export default ExpenseScreen;
I am trying to import the context into the "expenseScreen" but it doesn't work.
The error message I have is " element type is invalid: expected a string or a class but got undefined. You likely forgot to export your component from the file it's defined in or you might have mixed up default and name imports. Check the render method of 'ExpenseScreen'".
What am I missing ?
Does the Expenseprovider exported in the App only applies for the 'homeScreen' ?
Thank you very much in advance and hope this is clear enough.
Related
Been trying many things but for I cannot get this working for the life of me. Been looking at various Context tutorials but no. Could you help me out?
App.js
import React from 'react'
import { createAppContainer, createSwitchNavigator } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
import { createBottomTabNavigator } from 'react-navigation-tabs';
import AccountScreen from './src/screens/AccountScreen'
import SigninScreen from './src/screens/SigninScreen'
import SignupScreen from './src/screens/SignupScreen'
import TrackCreateScreen from './src/screens/TrackCreateScreen'
import TrackDetailScreen from './src/screens/TrackDetailScreen'
import TrackListScreen from './src/screens/TrackListScreen'
import UserProvider from './src/context/appContext'
const switchNavigator = createSwitchNavigator({
loginFlow: createStackNavigator({
Signup: SignupScreen,
Signin: SigninScreen
}),
mainFlow: createBottomTabNavigator({
trackListFlow: createStackNavigator({
TrackList: TrackListScreen,
TrackDetail: TrackDetailScreen
}),
TrackCreate: TrackCreateScreen,
Account: AccountScreen
})
})
const App = createAppContainer(switchNavigator)
export default () => {
return (
<UserProvider value={'hey'}>
<App />
</UserContext.Provider>
)
}
appContext.js
import React, { createContext } from 'react'
const UserContext = React.createContext()
export const UserProvider = UserContext.Provider
export const UserConsumer = UserContext.Consumer
export default UserContext
SignupScreen.js
import React, { useState, useContext, Component } from 'react'
import { View, StyleSheet, Button } from 'react-native'
import { Text, Input } from 'react-native-elements'
import Spacer from '../components/Spacer'
import { signUpUser } from '../functions/functions.js'
import { UserContext } from '../context/appContext.js'
const SignupScreen = ({ navigation, value }) => {
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
return (
<View style={styles.container}>
<Spacer>
<Text h3>Sign up for goodgrowth</Text>
</Spacer>
<Input
label="Email"
value={email}
onChangeText={setEmail}
autoCapitalize="none"
autoCorrect={false}
/>
<Spacer />
<Input
secureTextEntry
label="Password"
value={password}
onChangeText={setPassword}
autoCapitalize="none"
autoCorrect={false}
/>
<Spacer>
<Button
title="Sign up"
onPress={() => signUpUser(email, password)}
/>
<Button
title="Sign in"
onPress={() => navigation.navigate('Signin')}
/>
</Spacer>
</View>
)
}
SignupScreen.navigationOptions = () => {
return {
header: null
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
marginBottom: 250
}
})
export default SignupScreen
TypeError: render is not a function. (In 'render(newValue)', 'render' is an instance of Object).
Why is this not working?
You have exported UserProvider as a named export but you are importing as default in App.js which gives you UserContext and not UserProvider
Also your syntax of UserProvider is incorrect.
Use it like
import { UserProvider } from './src/context/appContext' // named import
...
export default () => {
return (
<UserProvider value={'hey'}>
<App />
</UserProvider>
)
}
Using the curly braces seemed to have done the trick! Thanks Shubham!
I also had to change the following in SignupScreen, so the other way around, from yes-curly-braces to no-curly-braces:"
import { UserContext } from '../context/appContext.js'
TO
import UserContext from '../context/appContext.js'
Because UserContext was the default export there. But it's still a React object, no? Why would it be 'undefined' if I left it in curly braces?
How I can re-render a web-view running inside a app built with react native. For exemple: The cart tab need to load the same url every time I click on it.
This is the cart class:
import React, { useState } from 'react';
import { ActivityIndicator, WebView, View, Button, ScrollView,
RefreshControl,
Text, } from 'react-native';
import Config from '../config';
export default class CarrinhoScreen extends React.Component {
reload() {
this.myWebView.reload()
}
render() {
return (
<>
<View style={{ flex: 1 }}>
<WebView
source={{ uri: 'https://www.genieshopp.com/checkout/cart/' }}
userAgent='bring-app'
startInLoadingState={true}
ref={(ref) => this.myWebView = ref}
/>
</View>
</>
)
}
};
Here is where the tabNavigator is created:
import React from 'react';
import { Platform } from 'react-native';
import { createStackNavigator, createBottomTabNavigator } from 'react-navigation';
import CarrinhoScreen from '../screens/CarrinhoScreen';
const config = Platform.select({
web: { headerMode: 'screen' },
default: {},
});
const CarrinhoStack = createStackNavigator(
{
Carrinho: CarrinhoScreen
},
config
);
CarrinhoStack.navigationOptions = {
tabBarLabel: 'Carrinho',
tabBarIcon: ({ focused }) => (
<TabBarIcon focused={focused} name={Platform.OS === 'ios' ? 'ios-cart' : 'md-cart'}/>
),
};
CarrinhoStack.path = '';
const tabNavigator = createBottomTabNavigator(
{
CarrinhoStack,
},
{
backBehavior: 'history'
}
);
tabNavigator.path = '';
export default tabNavigator;
I know there is the myWebView.reload(), but I want to know how I reload it when the bottom tab is switched or when I click on the same icon.
Solved by putting resetOnBlur: CarrinhoScreen after backBehavior: history
You can put any other screen you want to reset on there.
I am trying to create react native application.But it is throwing error. I used react-native-navigation.
(I am trying to create react native application.But it is throwing error. I used react-native-navigation. )
import { createAppContainer, createSwitchNavigator } from "react-navigation";
import { createStackNavigator } from "react-navigation-stack";
import { createBottomTabNavigator } from "react-navigation-tabs";
import DashboardScreen from "./src/component/Dashboard";
import LoginScreen from "./src/component/Auth/Login";
import RegisterScreen from "./src/component/Auth/Register";
const AppStack = createStackNavigator({ Dashboard: DashboardScreen });
const AuthStack = createBottomTabNavigator({
SignIn: LoginScreen,
Register: RegisterScreen
});
export const RootNaviation = () => {
return createAppContainer(
createSwitchNavigator(
{
Auth: AuthStack,
App: AppStack
},
{ initialRouteName: "Auth" }
)
);
};
App File
import React from "react";
import { StyleSheet, Text, View, Button } from "react-native";
import { SwitchNavigator } from "./Router";
const Nav = SwitchNavigator();
export default function App() {
return (
<View style={styles.container}>
<Button title="dafdlka" />
<Nav />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center"
}
});
enter image description here
You have never created a variable called SwitchNavigator.
You can use RootNaviation
import { RootNaviation } from "./Router"
...
export default function App() {
return (
<View style={styles.container}>
<Button title="dafdlka" />
<RootNaviation />
</View>
);
}
I get this error that getInputData is undefined, please what am I doing wrong?
getInputData simply gets the users inputs....I'm using redux. I defined getInputData in my function called handleInput or is it not well defined......
import React from "react";
import styles from "./style";
import { Text } from "react-native";
import { View, Input, InputGroup } from "native-base";
import Icon from "react-native-vector-icons/FontAwesome";
import { SearchBar } from "react-native-elements";
export const SearchBox = ({ getInputData }) => {
const handleInput = (key, val) => {
getInputData({
key,
value: val
});
};
return (
<View style={styles.searchBox}>
<View style={styles.inputWrapper}>
<Text style={styles.label}>PICK UP</Text>
<InputGroup>
<Icon name="search" size={15} color="#FF5E3A" />
<Input
style={styles.inputSearch}
placeholder="Enter Pickup Location"
onChangeText={handleInput.bind(this, "pickUp")}
/>
</InputGroup>
</View>
<View style={styles.inputWrapper}>
<Text style={styles.label}>DROP OFF</Text>
<InputGroup>
<Icon name="search" size={15} color="#FF5E3A" />
<Input
style={styles.inputSearch}
placeholder="Enter Drop Off Location"
onChangeText={handleInput.bind(this, "dropOff")}
/>
</InputGroup>
</View>
</View>
);
};
export default SearchBox;
this is my mapContainer.js where inputData is passed down as a prop to SearchBox.
import React from 'react';
import styles from './style';
import {View} from 'native-base';
import MapView from 'react-native-maps';
import SearchBox from '../SearchBox';
import SearchResults from '../SearchResults';
export const MapContainer= ({region, getInputData}) => {
return(
<View style={styles.container}>
<MapView
provider={MapView.PROVIDER_GOOGLE}
style={styles.map}
region={region}
>
<MapView.Marker
coordinate={region}
pinColor="green"/>
</MapView>
<SearchBox getInputData={getInputData}/>
<SearchResults/>
</View>
)
}
export default MapContainer
This is where I connect mapStateToProps to my mapActionCreators
import {connect} from "react-redux";
import {
getCurrentLocation,
getInputData,
} from '../../actions/currentLocation';
import { MapContainer } from '../MapContainer';
import Home from "../../screens/Home";
const mapStateToProps=(state)=>({
region:state.region,
inputData:state.inputData || {}
});
const mapActionCreators = {
getCurrentLocation,
getInputData,
};
export default connect(mapStateToProps,mapActionCreators)(Home);
this is my Home code.
import React from 'react';
import { View, Text } from 'react-native';
import styles from './styles';
import { Container} from 'native-base';
import { MapContainer} from '../../components/MapContainer';
import GetLocation from 'react-native-get-location'
import {Dimensions} from "react-native";
const {width,height}=Dimensions.get("window");
const ASPECT_RATIO=width/height;
const LATITUDE_DELTA=0.922;
const LONGITUDE_DELTA=ASPECT_RATIO*LATITUDE_DELTA
class Home extends React.Component{
constructor(props){
super(props);
this.state={
latitude:3.14662,
longitude:101.6984,
latitudeDelta:LATITUDE_DELTA,
longitudeDelta:LONGITUDE_DELTA
}
}
componentDidMount(){
GetLocation.getCurrentPosition({
enableHighAccuracy: true,
timeout: 15000,
})
.then(location => {
this.setState({
latitude:location.latitude,
longitude:location.longitude
})
console.log(location)
console.log(this.state.longitude);
})
.catch(error => {
const { code, message } = error;
console.warn(code, message);
}) }
render(){
const region={
latitude:this.state.latitude,
longitude:this.state.longitude,
latitudeDelta:this.state.latitudeDelta,
longitudeDelta:this.state.longitudeDelta
}
return(
<Container>
<MapContainer region={region} getInputData={this.props.getInputData} />
</Container>
);
}
}
export default Home;
You should use connect on the Home page like
import React from 'react';
import {connect} from "react-redux";
import { View, Text } from 'react-native';
import styles from './styles';
import { Container} from 'native-base';
import { MapContainer} from '../../components/MapContainer';
import GetLocation from 'react-native-get-location'
import {Dimensions} from "react-native";
import {
getCurrentLocation,
getInputData,
} from '../../actions/currentLocation';
const {width,height}=Dimensions.get("window");
const ASPECT_RATIO=width/height;
const LATITUDE_DELTA=0.922;
const LONGITUDE_DELTA=ASPECT_RATIO*LATITUDE_DELTA
class Home extends React.Component{
constructor(props){
super(props);
this.state={
latitude:3.14662,
longitude:101.6984,
latitudeDelta:LATITUDE_DELTA,
longitudeDelta:LONGITUDE_DELTA
}
}
componentDidMount(){
GetLocation.getCurrentPosition({
enableHighAccuracy: true,
timeout: 15000,
})
.then(location => {
this.setState({
latitude:location.latitude,
longitude:location.longitude
})
console.log(location)
console.log(this.state.longitude);
})
.catch(error => {
const { code, message } = error;
console.warn(code, message);
}) }
render(){
const region={
latitude:this.state.latitude,
longitude:this.state.longitude,
latitudeDelta:this.state.latitudeDelta,
longitudeDelta:this.state.longitudeDelta
}
return(
<Container>
<MapContainer region={region} getInputData={this.props.getInputData} />
</Container>
);
}
}
const mapStateToProps=(state)=>({
region:state.region,
inputData:state.inputData || {}
});
const mapActionCreators = {
getCurrentLocation,
getInputData,
};
export default connect(mapStateToProps,mapActionCreators)(Home);
I created a drawer (react-navigation) in Routes.js and I have a Button in HamburgerBtn.js. I wish to invoke the call on the button to open the drawer with my button. I do not understand how to get this even from outside of routes into the button.
#HamburgerBtn.js;import Hamburger from 'react-native-hamburger';
import React, {Component} from 'react';
import styles from './Component.style';
import {
Text,
View
} from 'react-native';
import {DrawerNavigator} from 'react-navigation';
import {NavigationActions} from 'react-navigation';
class HamburgerBtn extends Component {
constructor(props){
super(props);
this.state = {
active: false,
}
}
openControlPanel = () => {
this.props.navigation.navigate('DrawerOpen'); // open drawer
};
render () {
//onPress={()=> {this.setState({active: !this.state.active});this.props.navigation.navigate('DrawerOpen');}}/>
return (
<View style={styles.hamburgerBtnHome}>
<Hamburger active={this.state.active}
type = "arrow"
color = "black"
onPress={()=> {this.props.openControlPanel()}}
/>
</View>
);
}
}
export default HamburgerBtn;
--routes.js--
import Connect from './Connect/Connect';
import Setup from './Setup/Setup';
import Update from './Update/Update';
import homePage from './homePage'
import SideMenu from './SideMenu/SideMenu';
import {DrawerNavigator} from 'react-navigation';
openControlPanel = () => {
this.props.navigation.navigate('DrawerOpen'); // open drawer
};
export default DrawerNavigator({
homePage: {
screen: homePage
},
Connect: {
screen: Connect
},
Setup: {
screen: Setup
},
Update: {
screen: Update
}
}, {
contentComponent: SideMenu,
drawerWidth: 300
});
--homepage.js--
import React, {Component} from 'react';
import {
Text,
View
} from 'react-native';
import Hamburger from './Components/HamburgerBtn';
class homePage extends Component {
render () {
return (
<View style={{padding: 50}}>
<Hamburger/>
<Text>
HomePage
</Text>
</View>
);
}
}
export default homePage;
--hamburger--
import Hamburger from 'react-native-hamburger';
import React, {Component} from 'react';
import styles from './Component.style';
import {
Text,
View
} from 'react-native';
import PropTypes from 'prop-types';
import {NavigationActions} from 'react-navigation';
class HamburgerBtn extends Component {
constructor(props){
super(props);
this.state = {
active: false,
}
}
onPress = () => {
this.setState({active: !this.state.active});
this.props.onPress();
};
render () {
//onPress={()=> {this.setState({active: !this.state.active});this.props.navigation.navigate('DrawerOpen');}}/>
return (
<View style={styles.hamburgerBtnHome}>
<Hamburger active={this.state.active}
type = "arrow"
color = "black"
onPress={() => this.onPress()}
/>
</View>
);
}
}
export default HamburgerBtn;
--homepage--
import React, {Component} from 'react';
import {
Text,
View
} from 'react-native';
import Hamburger from './Components/HamburgerBtn';
class homePage extends Component {
openControlPanel = () => {
this.props.navigation.navigate('DrawerOpen'); // open drawer
};
render () {
return (
<View style={{padding: 50}}>
<Hamburger onPress={() => this.openControlPanel()} />
<Text>
HomePage
</Text>
</View>
);
}
}
export default homePage;