React Native - "Objects are not valid as React child" - reactjs

Problem
I'm trying to import a functional component I created into my React class component, and I receive the following error:
"Invariant Violation: Objects are not valid as a React child (found: object with keys {width, height, backgroundColor, textAlign, fontSize, alignSelf, color, margin, padding, borderRadius}). If you meant to render a collection of children, use an array instead."
I can't figure out why. I've tried changing the child component to a class based component but this didn't help. I also commented out the stylesheet in child component but then I still receive a similar error:
"Invariant Violation: 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."
Code
Parent Component
import React, {Component} from 'react';
import {
StyleSheet,
View,
Text,
Image,
TextInput,
TouchableOpacity,
TouchableWithoutFeedback,
Linking,
ScrollView
} from 'react-native';
import CustomTextInput from '../../Components/CustomTextInput/CustomTextInput';
export default class SignupScreen extends React.Component{
constructor(props) {
super();
this.state = {
ageConfirmed: false
}
}
render(){
return(
<View style={styles.container}>
<ScrollView
contentContainerStyle={styles.scrollView}
keyboardDismissMode={'on-drag'}
pinchGestureEnabled={false}
>
<CustomTextInput>
autoCorrect={false}
autoFocus={true}
placeholder={'Fortnite username'}
placeholderTextColor={'white'}
</CustomTextInput>
</ScrollView>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'white',
alignItems: 'center'
},
scrollView: {
flex: 1,
backgroundColor: 'white',
alignItems: 'center'
}
})
Child Component
import React from 'react';
import { TextInput, StyleSheet } from 'react-native';
import { windowWidth, windowHeight } from '../../Constants';
export default CustomTextInput = (
onChangeText,
autoCorrect,
autoFocus,
placeholder,
placeholderTextColor
) => {
return (
<TextInput>
style={styles.CustomTextInput}
{/* onChangeText={onChangeText} */}
autoCorrect={autoCorrect}
autoFocus={autoFocus}
placeholder={placeholder}
placeholderTextColor={placeholderTextColor}
</TextInput>
);
}
const styles = StyleSheet.create({
CustomTextInput: {
width: windowWidth*0.54,
height: windowHeight*0.036,
backgroundColor: 'blue',
textAlign: 'center',
fontSize: windowHeight*0.03,
alignSelf: 'center',
color: 'white',
margin: windowHeight*0.01,
padding: 0,
borderRadius: windowHeight*0.015 //TODO: assess if this is the right way to calc radius
}
});

child component
import React from 'react';
import { TextInput, StyleSheet } from 'react-native';
import { windowWidth, windowHeight } from '../../Constants';
export default ({
onChangeText,
autoCorrect,
autoFocus,
placeholder,
placeholderTextColor
}) => {
return (
<TextInput
style={styles.CustomTextInput}
autoCorrect={autoCorrect}
autoFocus={autoFocus}
placeholder={placeholder}
placeholderTextColor={placeholderTextColor}
/>
);
}
const styles = StyleSheet.create({
CustomTextInput: {
width: windowWidth*0.54,
height: windowHeight*0.036,
backgroundColor: 'blue',
textAlign: 'center',
fontSize: windowHeight*0.03,
alignSelf: 'center',
color: 'white',
margin: windowHeight*0.01,
padding: 0,
borderRadius: windowHeight*0.015 //TODO: assess if this is the right way to calc radius
}
});

There is a typo in both files. You have the component properties inside the tag whereas it should be defined as attributes of the tag, like so:
<CustomTextInput
autoCorrect={false}
autoFocus={true}
placeholder='Fortnite username'
placeholderTextColor='white'
/>
Sames goes for <TextInput />.

Related

React Native - React Navigation Cannot use Hooks in DrawerContent

I am developing an e-commerce application using React Native and I am trying to use useState in the drawerContent and it tells me this
Error: Invalid hook call. Hooks can only be called inside of the body
of a function component. This could happen for one of the following
reasons:
You might have mismatching versions of React and the renderer (such as React DOM)
You might be breaking the Rules of Hooks
You might have more than one copy of React in the same app
Thank you in advance for your answers.
Here's the code
import React, { useState } from 'react'
import { View, Text, TouchableOpacity, FlatList, StyleSheet, StatusBar } from 'react-native'
import IonIcons from "react-native-vector-icons/Ionicons"
import { categories } from '../../../services/DataTest'
import DrawerSearch from './DrawerSearch'
import DrawerItem from './DrawerItem'
export default function DrawerContent (props) {
const [search, setSearch] = useState("");
return (
<View>
<TouchableOpacity
style={styles.customDrawerTouch}
>
<View style={styles.backButtonRow}>
<IonIcons
name="ios-arrow-back"
size={25}
style={styles.customDrawerIcon}
color="#666666"
/>
<Text style={{ color: '#666666' }}>Back to Components</Text>
</View>
</TouchableOpacity>
<DrawerSearch value={search} setValue={setSearch}/>
<FlatList
data={categories}
keyExtractor={(item, index) => index.toString()}
renderItem={DrawerItem}
/>
</View>
);
}
const styles = StyleSheet.create({
customDrawerTouch: {
marginTop: StatusBar.currentHeight,
paddingLeft: 13,
paddingTop: 15,
},
customDrawerIcon: {
paddingRight: 10
},
backButtonRow: {
flexDirection: 'row',
alignItems: 'center',
paddingBottom: 17,
paddingLeft: 3,
borderBottomColor: '#F0F0F0',
borderBottomWidth: 1,
},
});
I'm using this component here
import * as React from 'react';
import { View, StyleSheet, StatusBar } from 'react-native';
import { createDrawerNavigator } from '#react-navigation/drawer';
import HeaderCategorie from '../../components/categories/index/HeaderCategorie';
import SearchBar from '../../components/home/index/SearchBar';
import DrawerContent from '../../components/categories/index/DrawerContent';
const Drawer = createDrawerNavigator();
function CategoriesScreen({ navigation }) {
return (
<View style={styles.container}>
<HeaderCategorie navigation={navigation}/>
<View style={styles.headerSearch}>
<SearchBar />
</View>
</View>
)
}
export default function Categories() {
return (
<Drawer.Navigator initialRouteName="Categories"
drawerContent={DrawerContent}
screenOptions={{headerShown:false}}
>
<Drawer.Screen name="Categories" component={CategoriesScreen} />
</Drawer.Navigator>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "flex-start",
alignItems: "center",
marginTop: StatusBar.currentHeight,
},
headerSearch: {
marginVertical:10
},
headerSearchText: {
fontWeight:"bold",
fontSize:35,
marginLeft:20,
marginVertical:15,
}
});
Reason: By using drawerContent={DrawerContent}, you are actually passing the reference of the DrawerContent function, which ends up breaking rules of hooks.
So to resolve this, change the following line:
<Drawer.Navigator initialRouteName="Categories"
drawerContent={DrawerContent}
screenOptions={{headerShown:false}}
>
to this
<Drawer.Navigator initialRouteName="Categories"
drawerContent={(props)=> <DrawerContent {...props}/>} // here
screenOptions={{headerShown:false}}
>
demo snack

Pass Function to Functional Component in React Native

I have an ItemForm component in a react-native expo app I would like to use for both Creates and Updates. It is a functional component which I am trying to pass a handler from a parent component to either create a new item or update an existing item. I am having trouble understanding how to pass the onPress handler down from the parent Class Component down to the functional child form Component.
Parent Component:
import React, { Component } from "react";
import { Text, View, StyleSheet } from 'react-native';
import Constants from 'expo-constants';
// You can import from local files
import ItemForm from './components/ItemForm';
// or any pure javascript modules available in npm
import { Card } from 'react-native-paper';
export default class App extends Component {
handleSubmit = ({ name }) => {
alert(name);
// todo: get form data and create or update database
}
render() {
return (
<View style={styles.container}>
<Card>
<ItemForm onSubmit={() => this.handleSubmit}/>
</Card>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
});
ItemForm.js
import React, { useState } from "react";
import { View, Text, StyleSheet } from "react-native";
import { Button, Card, Icon, Input } from "react-native-elements";
export default function ItemForm({ onSubmit }) {
const [name, setName] = useState("");
return (
<View style={styles.container}>
<View style={styles.header}>
<Text style={styles.headerText}>Add an Item</Text>
</View>
<Card
containerStyle={{
height: "80%",
margin: 0,
elevation: 1,
borderWidth: 0,
shadowOpacity: 0,
shadowRadius: 0,
}}
>
<Input
label="Item Name"
labelStyle={styles.itemText}
placeholder="Name Here"
onChangeText={(name) => setName(name)}
/>
<Button
icon={
<Icon
name="check-circle"
size={20}
style={{ paddingRight: 10 }}
onPress={onSubmit({name: name})}
/>
}
title="Save Item"
/>
</Card>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: "column",
},
header: {
alignItems: "center",
paddingTop: 40,
},
headerText: {
fontSize: 32,
},
itemText: {
fontSize: 25,
}
});
This is currently throwing:
onSubmit is not a function. (In 'onSubmit({name: name})', 'onSubmit' is undefined)
I've tried various different syntaxes of passing or calling the function by reading the docs here but I run into a lot of errors like Please attach a method to this component and I can't seem to get past this?
onPress should be a function that calls onSubmit, not the return value of calling onSubmit (onPress={onSubmit({name: name})}).
onPress needs to be on the Button.
You need to pass down this.handleSubmit from the parent component, and not a function that returns this.handleSubmit (onSubmit={() => this.handleSubmit}):
So in App:
<ItemForm onSubmit={this.handleSubmit}/>
In ItemForm:
<Button
onPress={() => onSubmit({name: name})}
icon={
<Icon
name="check-circle"
size={20}
style={{ paddingRight: 10 }}
/>
}
title="Save Item"
/>
demo

Cannot see UI in react-native for <TextInput>

I am starting with React-Native. I was able to see the <Text>. Then I progressed in adding my <TextInput>
import React from 'react';
import { StyleSheet, Text, View, TextInput } from 'react-native';
export default class App extends Component {
state = {
placeName: ''
}
placeNameChangedHandler = event => {
alert(event)
}
render(){
return (
<View style={styles.container}>
<Text>Ayman</Text>
<TextInput
style={{width:300, borderColor:"black"}}
value={this.state.placeName}
onChangeText={this.placeNameChangedHandler}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
I am able to bundle my Javascript app, but the UI shows a blank screen.
Note that I'm a novice and I'm using expo on my phone for UI device.
Add borderWidth: 1 in TextInput styles and it will show the empty textinput.

Invariant Violation: Element type is invalid

I am trying to clean up my styles by using a StyleSheet, but I can't seem to get it to work. I believe the error (seen below) is caused when I attempt to create a StyleSheet (const styles = EStyleSheet.create.
Note I am using react-native-extended-stylesheet However this is not the problem. This also happens with react-native's stylesheet.
This a picture of the error:
This this my code:
import React, { Component } from "react";
import {
View,
Text,
Button,
Image,
StyleSheet,
TextInput,
KeyboardAvoidingView,
TouchableOpacity
} from "react-native";
export default class Login extends Component {
render() {
return (
<View style={styles.wrapper}>
<Text>Login screen </Text>
<KeyboardAvoidingView behavior="padding" style={styles.loginContainer}>
<TextInput
placeholder="username or email"
placeholderTextColor='whitesmoke'
style={styles.input}
/>
<TextInput
placeholder="password"
secureTextEntry
placeholderTextColor='whitesmoke'
style={styles.input}
/>
<TouchableOpacity style={styles.loginbutton} onPress={() => this.props.navigation.navigate("Grades")}>
<Text style={{
textAlign: 'center',
color: "whitesmoke",
fontWeight: '700',
}}>
Login
</Text>
</TouchableOpacity>
</KeyboardAvoidingView>
</View>
);
}
}
const styles = StyleSheet.create({
loginContainer: {
paddingHorizontal: 9,
backgroundColor: "red"
},
input: {
paddingHorizontal: 10,
marginBottom: 10,
color: '#f1c40f', //sunflower color
backgroundColor: '#3498db',
},
logo: {
width: 231,
height: 231
},
wrapper: {
flex: 1,
alignItems: "center",
justifyContent: "center"
}
});
Here is my app.js.
import React from "react";
import { Font } from "expo";
import { Root } from "./app/router";
import { FontError } from "./app/components/fontError";
export default class App extends React.Component {
state = {
fontLoaded: false
};
async componentDidMount() {
await Font.loadAsync({
Arial: require("./app/resources/Arial.ttf")
});
this.setState({ fontLoaded: true });
}
render() {
if (!this.state.fontLoaded) return <FontError/>;
return <Root />;
}
// ...
}
My root component is router.js, I am using react-navigation.
import React, { Component } from "react";
import { createStackNavigator } from "react-navigation";
import {
Login,
Grades,
} from "./screens";
export const Root = createStackNavigator({
Login: {screen: Login},
Grades: {screen: Grades},
});
Feel free to ask me to append any additional information.
Thanks for your help in advance.
To fix my error I just re-cloned the repo and added back in all the code I wrote.
Thankfully I didn't push this error to the master branch.
This fixed the error.
*note in the process I got rid off react-native-extended-stylesheet, so it might have been cause of error.

How to add stateless component to a touchable component

I am trying to add a stateless component to my button.
const button = ({onButtonPress, buttonText}) => {
return (
<TouchableHighlight
onPress={() => onButtonPress()}>
<ButtonContent text={buttonText}/>
</TouchableHighlight>
)
};
and get this error:
Warning: Stateless function components cannot be given refs (See ref "childRef"
in StatelessComponent created by TouchableHighlight).
Attempts to access this ref will fail.
I have read up on the issue but I am still new to javascript and RN and have not found a solution. Any help would be appreciated.
full code:
GlossaryButtonContent:
import React from 'react';
import {
View,
Text,
Image,
StyleSheet
} from 'react-native';
import Colours from '../constants/Colours';
import {
arrowForwardDark,
starDarkFill
} from '../assets/icons';
type Props = {
text: string,
showFavButton?: boolean
}
export default ({text, showFavButton} : Props) => {
return (
<View style={styles.container}>
{showFavButton &&
<Image
style={styles.star}
source={starDarkFill}/>}
<Text style={[styles.text, showFavButton && styles.favButton]}>
{showFavButton ? 'Favourites' : text}
</Text>
<Image
style={styles.image}
source={arrowForwardDark}
opacity={showFavButton ? .5 : 1}/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'row',
alignItems: 'center'
},
favButton: {
marginLeft: 10,
color: Colours.darkTextHalf
},
text: {
flex: 1,
paddingTop: 5,
marginLeft: 20,
fontFamily: 'Bariol-Bold',
fontSize: 24,
color: Colours.darkText
},
image: {
marginRight: 20
},
star: {
marginLeft: 10
}
});
GlossaryButton:
import React from 'react';
import {
TouchableHighlight,
StyleSheet
} from 'react-native';
import Colours from '../constants/Colours';
import ShadowedBox from './ShadowedBox';
import GlossaryButtonContent from './GlossaryButtonContent';
type Props = {
buttonText: string,
onButtonPress: Function,
rowID: number,
sectionID?: string,
showFavButton?: boolean
}
export default ({buttonText, onButtonPress, rowID, sectionID, showFavButton} : Props) => {
return (
<ShadowedBox
style={styles.container}
backColor={showFavButton && Colours.yellow}>
<TouchableHighlight
style={styles.button}
underlayColor={Colours.green}
onPress={() => onButtonPress(rowID, sectionID)}>
<GlossaryButtonContent
text={buttonText}
showFavButton={showFavButton}/>
</TouchableHighlight>
</ShadowedBox>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
height: 60,
marginBottom: 10,
borderRadius: 5
},
button: {
flex: 1,
borderRadius: 5
}
});
Basically, Stateless components cannot have refs.
So, having a stateless component in the middle of the render tree will create a void in the ref chain, meaning you cannot access lower-down components.
So, the problem comes from trying to do this:
let Stateless = (props) => (
<div />
);
let Wrapper = React.createClass({
render() {
return <Stateless ref="stateeee" />
}
});
TouchableHighlight needs to give a ref to its child. And this triggers that warning.
Answer:
You can't actually make a stateless component a child of TouchableHighlight
Solution:
Use createClass or class to create the child of TouchableHighlight, that is GlossaryButtonContent.
See this github issue for more info and this one

Resources