i'm building application with ReactNative and Expo, i building component called Header showing the title of each screen,
so i send props of name on each time render the component
<Header title={"Home Screen"}/>
Header.js comoment
import React,{ useState } from 'react';
import { Text, View, Image,StyleSheet} from 'react-native';
import Icon from 'react-native-vector-icons/Feather';
import { useNavigation } from "#react-navigation/native";
const Header=( navigation, title) =>{
const { navigate } = useNavigation();
return(
<View style={styles.container}>
<Icon name="user" size={28}/>
<Text style={{fontWeight:'bold'}} >{title}</Text>
<Icon name="bell" size={28} />
</View>
)
}
export default Header;
const styles = StyleSheet.create({
container:{
position:"absolute",
display:'flex',
justifyContent: 'space-between',
flexDirection:'row',
height: 60,
top:10 ,
left:6,
right:6,
elevation:0,
backgroundColor: '#fff',
alignItems: 'center',
}
})
this error showing:
Error: Objects are not valid as a React child (found: object with keys {}). If you meant to render a collection of children, use an array instead.
You just missed to de-structure your props in Header. Simply change your Header component to have
const Header=({ title }) =>{ // added {} to de-structure your props
const { navigate } = useNavigation();
return(
<View style={styles.container}>
<Icon name="user" size={28}/>
<Text style={{fontWeight:'bold'}} >{title}</Text>
<Icon name="bell" size={28} />
</View>
)
}
Related
I am trying to understand how to use useRef in React Native and get the children of a View element, but I couldn't figure out to achieve it.
I am trying to use the .focus method in the TextInput component on press on the TouchableOpacity
Declaration:
const input = useRef(null);
TextInputComponent:
<View ref={input}>
<Tex>Email</Text>
<TextInput placeholder=""/>
</View>
Element:
<TouchableOpacity onPress={() => {}}>
<TextInputComponent />
</TouchableOpacity>
i tried input.current.children, but it returns undefined.
This is a working example of how to achieve what you want using on a basic expo init project on TypeScript:
App.tsx
import { StatusBar } from "expo-status-bar";
import { StyleSheet, Text, View, TextInput, TouchableOpacity} from "react-native";
import { useRef, forwardRef} from "react";
const TextInputComponent = forwardRef<TextInput>((props, ref) => {
return (
<View>
<Text>Email</Text>
<TextInput ref={ref} placeholder="Some placeholder" />
</View>
);
});
export default function App() {
const input = useRef<TextInput>(null)
return (
<View style={styles.container}>
<Text>Open up App.tsx to start working on your app!</Text>
<StatusBar style="auto" />
<TouchableOpacity onPress={() => {
input.current?.focus();
}}>
<TextInputComponent ref={input} />
</TouchableOpacity>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
});
In this case it is more practical to use a forwardRef so you don't have to loop through the children of the View component to pass a ref from the component (App in this case) that is using TextInputComponent.
I'm having a in react native which cannot call function component of gorhom/bottom-sheet and import to another component. Below is my code and error.
Function Component
import React, {useCallback, useMemo, useRef} from 'react';
import {View, Text, StyleSheet, Button} from 'react-native';
import {BottomSheetModal, BottomSheetModalProvider} from '#gorhom/bottom-sheet';
const BottomModal = () => {
const snapPoints = useMemo(() => ['25%', '50%'], []);
// ref
const bottomSheetModalRef = useRef<BottomSheetModal>(null);
// variables
// callbacks
const handlePresentModalPress = useCallback(() => {
bottomSheetModalRef.current?.present();
}, []);
const handleSheetChanges = useCallback((index: number) => {
console.log('handleSheetChanges', index);
}, []);
// renders
return (
<BottomSheetModalProvider>
<View style={styles.container}>
<Button
onPress={handlePresentModalPress}
title="Present Modal"
color="black"
/>
<BottomSheetModal
ref={bottomSheetModalRef}
index={1}
snapPoints={snapPoints}
onChange={handleSheetChanges}>
<View style={styles.contentContainer}>
<Text>Awesome 🎉</Text>
</View>
</BottomSheetModal>
</View>
</BottomSheetModalProvider>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 24,
justifyContent: 'center',
backgroundColor: 'grey',
},
contentContainer: {
flex: 1,
alignItems: 'center',
},
});
export default BottomModal;
Import it to use in another function component
<TouchableOpacity onPress={BottomModal}>
<Icon
size={28}
style={{marginRight: 20, color: Colors.grey2, marginTop: 16}}
name="calendar-outline"
/>
</TouchableOpacity>
Error
Invalid hook call. Hooks can only be called inside of the body of a function component. This could happend for one of the following reasons
The onPress function for the TouchableOpacity seems to be a problem here. Use some state to show or hide the BottomModel accordingly
const [isBottomModalOpen, setIsBottomModalOpen] = useState(false);
And then for the Touchable Opacity you set the state to be true and render the Modal
<TouchableOpacity onPress={BottomModal}>
<Icon
size={28}
style={{marginRight: 20, color: Colors.grey2, marginTop: 16}}
name="calendar-outline"
/>
</TouchableOpacity>
And then render the Modal conditionally if the setIsBottomModalOpen state is set to true
I got this error when trying to import and use another component that I have created in another file. And I got an error like this :
Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) 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 named imports.
Check the render method of `Sidebar`.
This is my code to export component as default component in customDrawer.js which file is same directory:
const Sidebar = ({ isDarkTheme, setIsDarkTheme, ...props }) => {
const handlePress = () => {
props.navigation.dispatch(DrawerActions.closeDrawer());
props.navigation.navigate("Settings");
};
const { colors } = useTheme();
const toggleTheme = () => {
setIsDarkTheme();
};
// console.log('navi--?',props.navigation);
return (
<Container style={{ backgroundColor: colors.background }}>
<Header
style={{
backgroundColor: colors.background,
borderBottomWidth: 0,
marginTop: 70,
borderWidth: 0,
}}
>
<StatusBar barStyle="dark-content" backgroundColor="#ffffff" />
<Right>
<Button transparent>
<TouchableOpacity onPress={() => handlePress()}>
{/* <Ionicons name="ios-options" size={28} color={colors.icon} /> */}
</TouchableOpacity>
</Button>
</Right>
</Header>
<Content>
<DrawerContentScrollView {...props}>
<DrawerItemList {...props} />
</DrawerContentScrollView>
<TouchableOpacity>
<View
style={{
display: "flex",
flexDirection: "row",
alignItems: "center",
paddingRight: 20,
paddingLeft: 20,
paddingTop: 10,
}}
>
<Text style={{ flex: 1, color: colors.text }}>Dark Theme</Text>
<View>
<Switch onValueChange={toggleTheme} value={isDarkTheme} />
</View>
</View>
</TouchableOpacity>
</Content>
</Container>
);
};
const styles = StyleSheet.create({});
export default Sidebar;
And then, in my App.js I have import components like this :
import Sidebar from "./customDrawer";
All imports I use in customDrawer.js :
import {
DrawerContentScrollView,
DrawerItemList,
} from "#react-navigation/drawer";
import { Button, Container, Content, Header, Right } from "native-base";
import React, { useState } from "react";
//import { Ionicons } from "#expo/vector-icons";
import { StyleSheet, Text, View, Switch } from "react-native";
import { StatusBar } from "react-native";
import { TouchableOpacity } from "react-native";
import { DrawerActions } from "#react-navigation/native";
import { useTheme } from "#react-navigation/native";
I'm init a test app whith expo-cli.
Install galio-framework
And put one of Toast in screens.But not show anything.
Is my code wrong?
this is my code in App.js
import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { StyleSheet, Text, View,Button } from 'react-native';
import {Toast,Block} from 'galio-framework';
export default function App() {
let isShow= true;
const { useNativeDriver } = this.props;
// const [isShow, setShow] = useState(false);
const setShow = (v)=>{
console.log("show change "+v);
isShow= v;
}
return (
<View style={styles.container}>
<Text>Open up App.js to start working on your app!</Text>
<StatusBar style="auto" />
<Button shadowless onPress={() => setShow(!isShow)} style={styles.btnCC}>click here for toast notifications</Button>
<Block style={styles.bl}>
<Toast isShow={true} positionIndicator="top">This is a top positioned toast</Toast>
<Toast isShow={isShow} positionIndicator="center" color="success">This is a center positioned toast</Toast>
</Block>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
bl:{
flex: 1,
height:200,
width:100,
// alignItems: 'center',
// justifyContent: 'center',
},
btnCC:{
width:200,
backgroundColor: '#006600',
}
});
Is my code wrong?Or is the framework bug?
isShow variable must be React state. Change code like this
export default function App() {
const [isShow, setShow] = React.useState(false)
const { useNativeDriver } = this.props;
return (
<View style={styles.container}>
<Text>Open up App.js to start working on your app!</Text>
<StatusBar style="auto" />
<Button shadowless onPress={() => setShow(!isShow)} style={styles.btnCC}>click here for toast notifications</Button>
<Block style={styles.bl}>
<Toast isShow={true} positionIndicator="top">This is a top positioned toast</Toast>
<Toast isShow={isShow} positionIndicator="center" color="success">This is a center positioned toast</Toast>
</Block>
</View>
);
}
I have an icon on the right side of my Header. When pressed I want to be transferred to another page. However, it comes up with an error.
This is my 'icon' screen:
import React, { Component } from 'react';
import { StyleSheet, View, Text, Image, TouchableOpacity } from 'react-native';
const Login = props => {
return (
<View style={{ flexDirection: 'row' }}>
<TouchableOpacity
onPress={() => {
props.navigation.navigate({routeName: 'Login'});}}>
<Image
source={{
uri:
'https://clipartart.com/images/login-icon-clipart-5.jpg',
}}
style={{
width: 40,
height: 40,
borderRadius: 40 / 2,
marginLeft: 15,
}}
/>
</TouchableOpacity>
</View>
);
}
export default Login;
This is my 'navigation' screen:
import {createStackNavigator} from 'react-navigation-stack';
import {createAppContainer} from 'react-navigation';
import React from 'react';
import Homepage from './screens/Homepage';
import Checkoutpage from './screens/Checkoutpage';
import Filterpage from './screens/Filterpage';
import Locationpage from './screens/Locationpage';
import Menupage from './screens/MenuPage';
import Welcomepage from './screens/Welcomepage';
import Loginpage from './screens/Loginpage';
import Finalpage from './screens/Finalpage';
import Login from './Components/Login';
const Navigation = createStackNavigator({
Home:Homepage,
Checkout: Checkoutpage,
Filter: Filterpage,
Location: Locationpage,
Menu: Menupage,
Welcome: Welcomepage,
Login: Loginpage,
Final: Finalpage
},
{
defaultNavigationOptions: {
headerRight:() => <Login/>
}
}
);
I'm very new to react-native. So if you found the problem, can you please explain thoroughly so I understand. Thank you!!
So it looks like you are expecting the navigation object to be part of the props passed to your <Login/> component. This object is only defined for screen components in react-navigate.
This means that you need to get access to the navigation functionality some other way. Luckily, this library provides you with the useNavigation() hook. So using that in your component would look something like:
// react-navigation v5+
import { useNavigation } from '#react-navigation/native';
const Login = () => {
const navigation = useNavigation();
return (
<View style={{ flexDirection: "row" }}>
<TouchableOpacity
onPress={() => {
navigation.navigate({ routeName: "Login" });
}}
>
<Image
source={{
uri: "https://clipartart.com/images/login-icon-clipart-5.jpg",
}}
style={{
width: 40,
height: 40,
borderRadius: 40 / 2,
marginLeft: 15,
}}
/>
</TouchableOpacity>
</View>
);
};
It seems to me you are using React Navigation v4.x , in order to use the useNavigation hook you need to upgrade to v5.x.
The navigation prop will be passed to all screens by default and you can use the useNavigation hook like #faelks suggested (if needed in other components).
UPGRADE TO v5 FIRST.
Here you have a little example for v5.x version:
import React from 'react'
import { Button, View, StyleSheet } from 'react-native'
import { NavigationContainer } from '#react-navigation/native'
import { createStackNavigator } from '#react-navigation/stack'
const Home = ({ navigation }) => (
<View style={styles.component}>
<Button title="Go to login" onPress={() => navigation.navigate('Login')} />
</View>
)
const Login = ({ navigation }) => (
<View style={styles.component}>
<Button title="Go back" onPress={() => navigation.goBack()} />
</View>
)
const Main = createStackNavigator()
const mainConfig = {
// configuration for this stack
initialRouteName: "Home",
}
export default props => (
<NavigationContainer>
<Main.Navigator {...mainConfig}>
<Main.Screen name="Home" component={Home} />
<Main.Screen name="Login" component={Login} />
{/* Other screens for this stack */}
</Main.Navigator>
</NavigationContainer>
)
const styles = StyleSheet.create({
component: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
}
})