I am with undefined is not an object (evaluating 'this.context.state') error at my React Native application using Expo.
context/index.js
import React, { Component } from "react";
const MyContext = React.createContext();
class MyProvider extends Component {
state = {
stage: 1,
players:[],
result:''
}
render(){
return(
<>
<MyContext.Provider value={{ state:this.state }}>
{this.props.children}
</MyContext.Provider>
</>
)
}
}
export {
MyProvider, MyContext
}
App.js file:
import { StatusBar } from 'expo-status-bar';
import { Component } from 'react';
import { StyleSheet, Text, View, ScrollView } from 'react-native';
import { MyContext } from './src/context';
import { MainStage } from './src/components/main_stage'
import { UserStage } from './src/components/user_stage'
import { MyProvider } from './src/context';
class App extends Component {
static contextType = MyContext;
render() {
return (
<MyProvider>
<ScrollView>
<View style={styles.container}>
{
this.context.state.stage === 1 ?
<MainStage />
:
<UserStage />
}
</View>
</ScrollView>
</MyProvider>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
export default App
In this App.js i just want to show a different view if the stage value at state object is 1 or 2.
main_stage.js just in case:
import { Text, View } from 'react-native';
const MainStage = () => {
return (
<View>
<Text>This is the main stage.</Text>
</View>
);
}
export default MainStage;
user_stage.js is exactly equal, the difference is just the content at <Text>.
Hope you guys can help me!
I try this and this solution without success at all.
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.
I just can not load custom fonts in an existing app using Expo, React Natvigation. I have an app that has Navigations set up in a core.js file as
import React from "react";
import {Text, View, StyleSheet} from "react-native";
import {NavigationContainer} from "#react-navigation/native";
import {createStackNavigator} from "#react-navigation/stack";
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import LoginScreen from "./login.js";
import RegisterScreen from "./register.js";
//import Home from "./home.js";
import PostAJobPage from "./secondTab.js";
import Ionicons from "react-native-vector-icons/Ionicons"
import store from "./store";
import SplashScreen from "./splashscreen";
import Home from "./homeStack.js";
import { Entypo } from '#expo/vector-icons';
import { MaterialCommunityIcons } from '#expo/vector-icons';
import SearchAJobStack from "./jobsearchstack.js";
const Tab = createBottomTabNavigator()
const Tabs = () => {
return(
//<NavigationContainer>
<Tab.Navigator initialRouteName = "home"
screenOptions = {({route}) => ({
tabBarIcon : ({focused,color, size}) => {
let iconName;
if(route.name == "home") {
iconName = "ios-home"
return <Ionicons name = {iconName} color = {color} size = {size}/>
}
else if(route.name == "postJob")
{
//iconName = "md-settings"
iconName = "briefcase"
return <Entypo name = {iconName} color = {color} size = {size}/>
}
else if (route.name == "searchJob")
{
iconName = "briefcase-search"
return <MaterialCommunityIcons name = {iconName} size={size} color= {color} />
}
//return <Ionicons name = {iconName} color = {color} size = {size}/>
}
})}
tabBarOptions = {{
style : {
height : 50
},
showLabel : false,
activeTintColor : "gold"
}
}>
<Tab.Screen name="home" component ={Home}/>
<Tab.Screen name="postJob" component ={PostAJobPage}/>
<Tab.Screen name="searchJob" component ={SearchAJobStack}/>
</Tab.Navigator>
//</NavigationContainer>
)
}
const Stack = createStackNavigator()
function Stacks() {
return(
<NavigationContainer>
<Stack.Navigator initialRouteName = "loadingPage">
<Stack.Screen
name = "loadingPage"
component = {SplashScreen}
options = {{
headerShown : false
}}/>
<Stack.Screen
name ="Main"
component = {Tabs}
options = {{
headerShown : false,
}}/>
<Stack.Screen name= "login"
component = {LoginScreen}
options = {{
title : "Login",
headerTitleAlign : "left"
}}/>
<Stack.Screen name= "register"
component = {RegisterScreen}
options = {{
title : "Register",
headerTitleAlign : "left",
}}/>
</Stack.Navigator>
</NavigationContainer>
)
}
export default class core extends React.Component {
render(){
return (
<Stacks/>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor : "#fff",
alignItems : "center",
justifyContent : "center",
}
})
I am importing this stacks in my App.js and have added the code to add custom fonts according to the Docs in Expo but if I change fontFamily: Pacifico to any of the screens it doesnot work
My app.js file is
import 'react-native-gesture-handler';
import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { StyleSheet, Text, View, Image } from 'react-native';
import Core from "./core.js";
import {Provider} from "react-redux";
import store from "./store.js";
import * as Font from "expo-font";
const customFonts = {
dancingScript : require("./assets/fonts/DancingScript-Regular.ttf"),
Pacifico : require("./assets/fonts/Pacifico-Regular.ttf"),
Inter : require("./assets/fonts/Inter-VariableFont.ttf"),
}
export default class App extends React.Component {
state = {
fontsLoaded : false,
}
async _loadFontsAsync() {
await Font.loadAsync(customFonts);
this.setState({ fontsLoaded: true });
}
componentDidMount() {
this._loadFontsAsync();
}
render(){
if(this.state.fontsLoaded)
{
return (
<Provider store = {store}>
<Core/>
</Provider>
);
}
else {
return(
<View style= {styles.container}>
<Image source = {require("./ajax-loader.gif")}/>
</View>
)
}
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
//fontFamily : "dancingScript",
},
});
I personally feel this is a better way to load custom fonts. I use this method in all my projects. To loadFonts create a folder called hooks where your App.js is located
Then, Install expo-app-loading & expo-font
Then inside hooks folder create a file called useFonts.js
Inside useFonts.js write like this
import * as Font from "expo-font";
export default useFonts = async () => {
await Font.loadAsync({
"Pacifico" : require("./assets/fonts/Pacifico-Regular.ttf"),
// All other fonts here
});
};.
Now in your App.js write like this
import * as Font from 'expo-font';
import AppLoading from 'expo-app-loading';
import React, { useState } from 'react';
import useFonts from './hooks/useFonts';
export default function App() {
const [IsReady, SetIsReady] = useState(false);
const LoadFonts = async () => {
await useFonts();
};
if (!IsReady) {
return (
<AppLoading
startAsync={LoadFonts}
onFinish={() => SetIsReady(true)}
onError={() => {}}
/>
);
}
return <View styles={styles.container}>{/* Code Here */}</View>;
}
Note: The above solution was for Function components.
For Class Component, you can do something like this
Working Example Here
import React from 'react';
import { StyleSheet, Text, View, Image } from 'react-native';
import useFonts from './hooks/useFonts';
export default class App extends React.Component {
state = {
fontsLoaded: false,
};
async _loadFontsAsync() {
await useFonts();
this.setState({ fontsLoaded: true });
}
componentDidMount() {
this._loadFontsAsync();
}
render() {
if (this.state.fontsLoaded) {
return (
<View style={styles.container}>
<Text>Fonts Loaded</Text>
<Text style={{ fontFamily: 'Helvetica' }}>Helvetica Text</Text>
<Text>Normal Text</Text>
</View>
);
} else {
return (
<View style={styles.container}>
<Image
source={{
uri:
'https://landerapp.com/blog/wp-content/uploads/2018/06/1_FFP1bisztXseQFbZ-WQedw-1.png',
}}
style={{ width: '100%', height: '100%' }}
/>
</View>
);
}
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
//fontFamily : "dancingScript",
},
});
this is how you can load your fonts in an expo app write the code in the entry point of your app which is mainly App.js
import { useFonts } from "expo-font";
const [fontsLoaded] = useFonts({
// Axiforma: require("./assets/fonts/Axiforma-Black.ttf"),
// BlackItalic: require("./assets/fonts/Axiforma-BlackItalic.ttf"),
Bold: require("./assets/fonts/Axiforma-Bold.ttf"),
// BoldItalic: require("./assets/fonts/Axiforma-BoldItalic.ttf"),
// Book: require("./assets/fonts/Axiforma-Book.ttf"),
// BookItalic: require("./assets/fonts/Axiforma-BookItalic.ttf"),
ExtraBold: require("./assets/fonts/Axiforma-ExtraBold.ttf"),
// ExtraBoldItalic: require("./assets/fonts/Axiforma-ExtraBoldItalic.ttf"),
// Heavy: require("./assets/fonts/Axiforma-Heavy.ttf"),
// HeavyItalic: require("./assets/fonts/Axiforma-HeavyItalic.ttf"),
// Italic: require("./assets/fonts/Axiforma-Italic.ttf"),
Light: require("./assets/fonts/Axiforma-Light.ttf"),
// LightItalic: require("./assets/fonts/Axiforma-LightItalic.ttf"),
Medium: require("./assets/fonts/Axiforma-Medium.ttf"),
// MediumItalic: require("./assets/fonts/Axiforma-MediumItalic.ttf"),
Regular: require("./assets/fonts/Axiforma-Regular.ttf"),
SemiBold: require("./assets/fonts/Axiforma-SemiBold.ttf"),
// SemiBoldItalic: require("./assets/fonts/Axiforma-SemiBoldItalic.ttf"),
Thin: require("./assets/fonts/Axiforma-Thin.ttf"),
// ThinItalic: require("./assets/fonts/Axiforma-ThinItalic.ttf"),
});
if (!fontsLoaded) return <AppLoading />;
Use #expo-google-fonts
Go to the project root from the terminal and type to install the font that wish, example:
expo install #expo-google-fonts/ubuntu
The explo cli will install all ubuntu fonts as a node module, look inside the path ./node_modules/#expo-google-fonts/ubuntu, all fonts are there.
Now, import the hook and the font styles that you wish from this font family, like this:
import { useFonts, Ubuntu_400Regular, Ubuntu_500Medium, Ubuntu_700Bold } from '#expo-google-fonts/ubuntu';
Then, load them inside your app using the hook:
let [fontsReady,fontsError] = useFonts({Ubuntu_400Regular, Ubuntu_500Medium, Ubuntu_700Bold});
fontsReady will be true when the fonts are ready to use and the fontsError will has the error reason if the app could not load the fonts.
To wait the fonts be ready, use expo-app-loading module and do something like this:
if (!fontsReady) return <AppLoading/>;
To choose the fonts that you wish to install on your project, visit https://directory.vercel.app/ , this will show all Google fonts and the import cmd in an easy way. Do not forget to include the useFonts hook.
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.
im try to get this code i found online working locally in visual code studio, but it only works online
this is the expo to the code and all the file, https://snack.expo.io/#git/github.com/israsotomayor/react-native-redux-shopping-cart-count
and this is the link to my error:
shoppingCart.js file
import React, { Component } from "react";
import {
View,
Text,
StyleSheet
} from "react-native";
import { createStackNavigator } from 'react-navigation-stack'
import HomeScreen from './containers/HomeScreen'
import ElectronicsScreen from './containers/ElectronicsScreen'
import BooksScreen from './containers/BooksScreen'
import ShoppingCartIcon from './containers/ShoppingCartIcon'
import CartScreen from './containers/CartScreen'
class ShoppingCart extends Component {
render() {
return (
<AppStackNavigator />
);
}
}
export default ShoppingCart;
const AppStackNavigator = createStackNavigator({
Home: HomeScreen,
Electronics: ElectronicsScreen,
Books: BooksScreen,
Cart: CartScreen
}, {
navigationOptions: {
headerTitle: 'Shopping App',
headerRight: (
<ShoppingCartIcon />
)
}
})
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center'
}
});
app.js file
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import ShoppingCart from './ShoppingCart'
import { Provider } from 'react-redux'
import store from './store'
export default class App extends React.Component {
render() {
return (
<Provider store={store}>
<ShoppingCart />
</Provider>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
just checked and this structure should work properly :
import React, { Component } from "react";
import {
View,
Text,
StyleSheet
} from "react-native";
import { createAppContainer } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack'
import HomeScreen from './containers/HomeScreen'
import ElectronicsScreen from './containers/ElectronicsScreen'
import BooksScreen from './containers/BooksScreen'
import ShoppingCartIcon from './containers/ShoppingCartIcon'
import CartScreen from './containers/CartScreen'
const AppStackNavigator = createStackNavigator({
Home: HomeScreen,
Electronics: ElectronicsScreen,
Books: BooksScreen,
Cart: CartScreen
}, {
navigationOptions: {
headerTitle: 'Shopping App',
headerRight: (
<ShoppingCartIcon />
)
}
})
export default createAppContainer (AppStackNavigator);
copy paste and it should work !!!