Invariant Violation error Object are not valid as a React Child - javascript

I'm trying to render a Segment, which will render a Photos or Reviews component, depending on which is selected. The renderSegments function is working and the console.log('Rendered Photos') is working. The issue seems to be how I'm returning the Photos component.
The Photos component should just be rendering the text "Photos" to the screen in the ScrollView of the View.js screen.
Error:
Error: Invariant Violation: Invariant Violation: Objects are not valid
as a React child (found: object with keys {_40, _65, _55, _72}). If
you meant to render a collection of children, use an array instead.
Photos.js
// Imports: Dependencies
import React, { Component } from "react";
import { Dimensions, View, SafeAreaView, StyleSheet, Text } from 'react-native';
// Screen Dimensions
const { height, width } = Dimensions.get('window');
// Component: Photos
export default class Photos extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<View style={styles.container}>
<Text style={styles.photos}>Photos</Text>
</View>
)
}
}
// Styles
const styles = StyleSheet.create({
container: {
width: width,
},
photos: {
fontFamily: 'System',
fontSize: 24,
fontWeight: '700',
color: '#000',
},
});
View.js
// Imports: Dependencies
import React, { Component } from "react";
import { Dimensions, SafeAreaView, ScrollView, StyleSheet, Text, View } from 'react-native';
import { Container, Header, Left, Body, Right, Button, Icon, Title, Segment, Content } from 'native-base';
// Imports: Components
import Photos from '../components/Photos';
import Reviews from '../components/Reviews';
// Screen Dimensions
const { height, width } = Dimensions.get('window');
// Screen: View
export default class View extends React.Component {
constructor(props) {
super(props);
this.state = {
segmentSelected: 'Photos',
};
}
// React Navigation: Options
static navigationOptions = {
headerStyle: {
elevation: 0,
shadowOpacity: 0,
borderBottomWidth: 0,
},
};
// Render Segments (Photos/Reviews)
renderSegments = async () => {
try {
console.log('Rendering Segments');
if (this.state.segmentSelected === 'Photos') {
console.log('Rendered Photos');
return (
<Photos />
)
}
if (this.state.segmentSelected === 'Reviews') {
console.log('Rendered Reviews');
return (
<Reviews />
)
}
}
catch (error) {
console.log(error);
}
}
render() {
return (
<SafeAreaView style={styles.container}>
<View style={styles.segmentContainer}>
<Segment style={{ width: width }} style={{ backgroundColor: '#fff'}}>
<Button
first
active={this.state.segmentSelected === 'Photos' ? true : false}
onPress={() => this.setState({ segmentSelected: 'Photos' })}
>
<Text style={{ color: this.state.segmentSelected === 'Photos' ? '#fff' : '#007AFF'}}> Photos </Text>
</Button>
<Button
last
active={this.state.segmentSelected === 'Reviews' ? true : false}
onPress={() => this.setState({ segmentSelected: 'Reviews' })}
>
<Text style={{ color: this.state.segmentSelected === 'Reviews' ? '#fff' : '#007AFF'}}> Reviews </Text>
</Button>
</Segment>
</View>
<ScrollView style={{ backgroundColor: 'green' }}>
<View>
{this.renderSegments()}
</View>
</ScrollView>
</SafeAreaView>
)
}
}
// Styles
const styles = StyleSheet.create({
container: {
flex: 1,
// justifyContent: 'center',
alignItems: 'center',
width: width,
},
segmentContainer: {
marginTop: 7,
marginBottom: 7,
borderColor: '#999999',
width: width,
borderBottomWidth: .2,
},
text: {
fontFamily: 'System',
fontSize: 16,
fontWeight: '400',
color: '#222222',
},
});

Related

Pass data between two components in React Native

I have a component that encapsulates three components one of them is the DrawerLayoutAndroid. Now I want to pass the reference of the drawer from the drawer component to the main component and then pass it to the header component so I can trigger it from the header component.
I have no idea how to do that.
Here is the main component 'cases.js'
import React, { Component } from 'react';
import { View, Text, StyleSheet, TouchableOpacity } from 'react-native';
import Header from '#components/header';
import BottomBar from '#components/bottom-bar';
import SideBar from '#components/drawer';
export default class Cases extends Component {
state = {
title : 'Cases'
}
change_text = () => {
this.setState({ title : 'Test' })
}
open_drawer = (ref) => {
ref.openDrawer();
}
close_drawer = (ref) => {
ref.closeDrawer();
}
render() {
return (
<SideBar style={ styles.container }>
<Header title={ this.state.title } change_text={ this.change_text } open={ this.state.side_bar } />
<View style={ styles.body }>
<Text style={ styles.text }> { this.state.name } </Text>
<TouchableOpacity onPress={ () => this.change_text() } style={ styles.button }>
<Text> Change State </Text>
</TouchableOpacity>
</View>
<BottomBar ref={ this.state.side_bar } />
</SideBar>
)
}
}
const styles = StyleSheet.create({
container : {
flex : 1,
flexDirection: 'column',
},
body : {
flex : 1,
backgroundColor: '#ccc',
justifyContent: 'center',
alignItems: 'center'
},
text : {
color : '#fff'
},
button : {
backgroundColor : '#eee',
paddingVertical: 5,
paddingHorizontal: 10
}
})
Here is my header:
import React, { Component } from 'react';
import { View, Text, StyleSheet, TouchableOpacity, Image } from 'react-native';
import DrawerLayoutAndroid from 'DrawerLayoutAndroid';
import LinearGradient from 'react-native-linear-gradient';
export default class Header extends Component {
change_text = () => {
this.props.change_text();
}
open = ()
render () {
return (
<LinearGradient start={{x: 0, y: 0}} end={{x: 1, y: 0}} colors={['#a4d294', '#3ac6f3']} style={ styles.header }>
<TouchableOpacity onPress={ () => this.props.change_text() }>
<Image source={ require('#media/images/add.png') } style={ styles.add_button } />
</TouchableOpacity>
<Text style={ styles.title }> { this.props.title } </Text>
<TouchableOpacity onPress={ () => this.props.open() }>
<Image source={ require('#media/images/more.png') } style={ styles.more_button } />
</TouchableOpacity>
</LinearGradient>
)
}
}
const styles = StyleSheet.create({
header : {
height: 70,
backgroundColor: '#eee',
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center'
},
title : {
color : '#fff',
textAlign: 'center',
fontSize: 20,
letterSpacing: 3
},
add_button : {
width: 30,
height: 30,
marginHorizontal: 10
},
more_button : {
width: 30,
height: 30,
marginHorizontal: 10
}
})
And here is my drawer.js
import React, { Component } from 'react';
import { View, Text } from 'react-native';
import DrawerLayoutAndroid from 'DrawerLayoutAndroid';
import LinearGradient from 'react-native-linear-gradient';
export default class Drawer extends Component {
render () {
const NavigationMenu = (
<LinearGradient start={{x: 0, y: 0}} end={{x: 0, y: 1}} colors={['#a4d294', '#3ac6f3']} style={{ flex: 1 }}>
<View style={{ flex : 6, justifyContent: 'center' }}>
<Text>He There</Text>
</View>
</LinearGradient>
)
return (
<DrawerLayoutAndroid
drawerWidth={250}
drawerPosition={ DrawerLayoutAndroid.positions.Right }
renderNavigationView={ () => NavigationMenu }
ref={ (drawer) => this.props.ref = drawer }
>
{ this.props.children }
</DrawerLayoutAndroid>
)
}
}
I am going to answer your question by giving a simple example.
Lets take 2 components parent and child. You want to pass some message from parent to child and get a callback from child to parent when an event occurs in child.
export default class Parent extends React.Component<any, any> {
callback (paramFromChild) => {
// implement what to do when certain event occurs in child component
}
render () {
<View>
<Child message={"some text"} callbackFromChild={this.callback}/>
</View>
}
}
Child component
Interface childProps {
message: string
callbackFromChild(paramFromChild);
}
export default class Child extends React.Component<childProps, any> {
render () {
<View>
<Button title={this.props.message} onPress={this.props.callbackFromChild("some message from child")}/>
</View>
}
}
In this way you can communicate between different components using props.

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.

Error while updating property 'accessibilityLabel' of a view managed by: RCTView TypeError: expected dynamic type `string', but had type `object'

I want to create some screen with stack and tabs navigator, but it seems not worked, it get error message like this error on virtual device...
Is this because the navigation or what?
This is my code
ConfirmActivation.js
import React, { Component } from 'react';
import { StyleSheet, Image } from 'react-native';
import { Container, Header, Content, Left, Right, Body, Text, StyleProvider,
Form, Item, Input, Label, Button, View } from 'native-base';
import { StackNavigator } from 'react-navigation';
import Icon from 'react-native-vector-icons/FontAwesome';
import getTheme from '../../../native-base-theme/components';
import material from '../../../native-base-theme/variables/material';
import Index from '../tabs/Index';
export default class sharpcs extends React.Component {
static navigationOptions = {
title: <Image source={require('../../assets/img/sharp_logo.png')} style={{width: 200, height: 50}} />,
header: null
}
render() {
return (
<AppNavigation/>
);
}
}
class ConfirmActivation extends Component{
static navigationOptions = {
title: <Image source={require('../../assets/img/sharp_logo.png')} style={{width: 200, height: 50}} />,
header: null
}
render() {
const { navigate } = this.props.navigation;
return (
<StyleProvider style={getTheme(material)}>
<Container style={styles.container} >
<Form style={styles.form} >
<Item floatingLabel>
<Label>Masukkan kode verifikasi</Label>
<Input keyboardType = 'numeric' maxLength = {13} />
</Item>
<View style={styles.buttonContainer} >
<Button
onPress={() =>
navigate('MainScreen')
} success style={{width: 125}} >
<Label style={{color: '#FFF', marginLeft: 24}} >
Lanjut
</Label>
</Button>
</View>
</Form>
</Container>
</StyleProvider>
);
}
}
const App = StackNavigator({
ThisScreen: { screen: ConfirmActivation },
MainScreen: { screen: Index }
});
const AppNavigation = () => (
<App />
);
const styles = StyleSheet.create({
form: {
flex: 2,
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center'
},
container: {
padding: 20
},
buttonContainer: {
marginTop: 20,
flexDirection: 'row',
alignSelf: 'flex-end'
}
});
Index.js
import React, { Component } from 'react';
export default class Index extends React.Component {
render() {
return null;
}
}
The cause of the error is the title in the navigationOptions in sharpcs class. It expects a string. You had provided it an image component. Although the image appears, but this error appears when navigating. So use instead of title, headerTitle

Reset to default slider value react-native

I try to create a reset button for the slider that will reset it to the initial value when pressed. My code doesn't show any error but the reset button doesn't work.
This is the Slider component:
import React, {Component} from 'react';
import {Slider,
Text,
StyleSheet,
View} from 'react-native';
import {ButtonReset} from './ResetButton.js'
export class SliderRoll extends Component {
state = {
value: 1,
};
resetSliderValue = () => this.setState({value : 1})
render() {
return (
<View style={styles.container}>
<Slider style={styles.slider}
minimumTrackTintColor={'blue'}
maximumTrackTintColor={'red'}
maximumValue = {2}
value= {this.state.value}
step={0.5}
onValueChange={(value) => this.setState({value: value})}
/>
<ButtonReset resetSliderValue = {this.state.resetSliderValue}/>
<Text style={styles.text} >
{this.state.value}
</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flexDirection:'column',
width: 150,
backgroundColor: 'pink',
marginLeft: 50,
justifyContent: 'center'
},
slider: {
width: 150,
},
text: {
fontSize: 20,
textAlign: 'center',
fontWeight: '500',
},
})
This is the Reset button:
import React, {Component} from 'react';
import {
Text,
View,
StyleSheet,
Image,
TouchableOpacity
} from 'react-native';
export class ButtonReset extends Component{
render(){
return(
<TouchableOpacity style = {styles.container}
onPress= {this.props.resetSliderValue}>
<Image
style={styles.button}
source={require('./restart.png')}
/>
</TouchableOpacity>
);
}
}
const styles = StyleSheet.create({
container: {
width: 50,
alignItems: 'center',
backgroundColor: 'pink',
marginLeft: 50,
marginTop: 10,
},
button: {
width:50,
height:50,
transform: [
{scale: 1}
]
}
})
Here is the problematic piece that stuck out right away:
<ButtonReset resetSliderValue = {this.state.resetSliderValue}/>
I believe it should be:
<ButtonReset resetSliderValue = {this.resetSliderValue}/>
Also, I believe you need to bind this so you can access this for setting state in the resetSliderValue function. I personally like to bind this once in the constructor for any functions that require it so no unnecessary rebinding during rendering:
constructor(props) {
super(props);
this.resetSliderValue = this.resetSliderValue.bind(this);
}

Children not rendering on state change

I'm working on an app in React-Native and I am trying to render a component with children. If I use the component directly it functions 100% as expected, but if I return it from a conditional(switch) statement it doesn't render children. However the logic is functioning properly because I can actually see the state change.
I have it working 100% properly via conditional usage in another component, but it won't work in this particular case. It's imported correctly because the button renders, but without the child text inside of it, thus displaying just the button with no label text.
App.js
import React, { Component } from 'react';
import { View } from 'react-native';
import firebase from 'firebase';
import { LoginForm } from './components/LoginForm';
import { Header, Button, Spinner } from './components/common';
class App extends Component {
state = { loggedIn: null };
componentWillMount() {
firebase.initializeApp({
apiKey: 'nope',
authDomain: 'nope',
databaseURL: 'nope',
projectId: 'nope',
storageBucket: 'nope',
messagingSenderId: 'nope'
});
firebase.auth().onAuthStateChanged((user) => {
if (user) {
this.setState({ loggedIn: true });
} else {
this.setState({ loggedIn: false });
}
});
}
renderContent() {
switch (this.state.loggedIn) {
case true:
return (
<Button onPress={() => firebase.auth().signOut()}>
Log Out
</Button>
);
case false:
return <LoginForm />;
default:
return <Spinner size="large" />;
}
}
render() {
return (
<View>
<Header headerText="Authentication" />
{this.renderContent()}
</View>
);
}
}
export default App;
Button.js
import React from 'react';
import { Text, TouchableOpacity } from 'react-native';
const Button = ({ onPress, children }) => {
const { buttonStyle, textStyle } = styles;
return (
<TouchableOpacity onPress={onPress} style={buttonStyle}>
<Text style={textStyle}>
{children}
</Text>
</TouchableOpacity>
);
};
const styles = {
buttonStyle: {
flex: 1,
alignSelf: 'stretch',
backgroundColor: '#fff',
borderRadius: 5,
borderWidth: 1,
borderColor: '#007aff',
marginLeft: 5,
marginRight: 5
},
textStyle: {
alignSelf: 'center',
color: '#007aff',
fontSize: 16,
fontWeight: '600',
paddingTop: 10,
paddingBottom: 10
}
};
export { Button };
The state change is in fact working properly, as I can see the state change, but when the button is rendered it does not render the child text "Log Out".
If I use the Log Out directly in the main render method it displays fine, but when I call it via the renderContent() method it does not display the "Log Out" text.
You should pass in the button text as a prop instead of as a child.
renderContent() {
switch (this.state.loggedIn) {
case true:
return <Button onPress={() => firebase.auth().signOut()} btnText="Log Out" />;
case false:
return <LoginForm />;
default:
return <Spinner size="large" />;
}
}
Button.js
import React from 'react';
import { Text, TouchableOpacity } from 'react-native';
const Button = ({ onPress, children }) => {
const { buttonStyle, textStyle } = styles;
return (
<TouchableOpacity onPress={onPress} style={buttonStyle}>
<Text style={textStyle}>
{this.props.btnText}
</Text>
</TouchableOpacity>
);
};
const styles = {
buttonStyle: {
flex: 1,
alignSelf: 'stretch',
backgroundColor: '#fff',
borderRadius: 5,
borderWidth: 1,
borderColor: '#007aff',
marginLeft: 5,
marginRight: 5
},
textStyle: {
alignSelf: 'center',
color: '#007aff',
fontSize: 16,
fontWeight: '600',
paddingTop: 10,
paddingBottom: 10
}
};
export { Button };

Categories