React native: Objects are not valid as React child - reactjs

I've really tried to read all over StackOverflow on this one since it's been asked many times before... but I can't find the solution to my error.
Invariant Violation: Objects are not valid as a React child (found: object with keys {id, title, desc, location, distance}).
I'm assuming there is something wrong in this file, not sure what thou...
PointOfInterestCluster.js
import React from 'react'
import { Text, View, TouchableOpacity,TouchableWithoutFeedback, ScrollView } from 'react-native'
import Styles from '../../constants/Styles';
export default class PointOfInterestCluster extends React.Component {
constructor(props) {
super(props)
this.state = {
data: this.props.data,
}
this.onMarkerPress = this.props.onMarkerPress.bind(this);
}
renderMarkers = (item, index) => {
console.log(item, index);
return (
<TouchableOpacity onPress={() => this.onMarkerPress(item)} key={'markerslist_'+index}>
<View style={[Styles.borderBottom, Styles.borderLight, Styles.padding]}>
<Text style={[Styles.text, Styles.textBold, Styles.textDark]}>{item.title}</Text>
</View>
</TouchableOpacity>
)
}
render() {
return (
<TouchableWithoutFeedback>
<View>
<ScrollView>
<Text style={[Styles.label, Styles.padding, Styles.borderBottom]}>
{this.props.data.length} enheter
</Text>
</ScrollView>
{this.state.data.map((item, index) => {this.renderMarker(item, index)})}
</View>
</TouchableWithoutFeedback>
);
}}
PointOfInterestCluster gets called liked this:
{this.state.currentCluster || this.state.currentMarker &&
<Overlay onClose={this.onCloseOverlay}>
{this.state.currentCluster &&
<PointOfInterestCluster onMarkerPress={this.onMarkerPress} data={this.state.currentCluster} poi={this.state.currentPOI}/>
}
{this.state.currentMarker &&
<PointOfInterest data={this.state.currentMarker} poi={this.state.currentPOI} />
}
</Overlay>
}

In the following line:
{this.state.data.map((item, index) => {this.renderMarker(item, index)})}
You're not really returning anything from the map function, because you have curly brackets around the this.renderMarker call. renderMarker gets called, but its result is being ignored.
You can change it to one of the following 3 alternatives which are all equivalent:
1.
1.
this.state.data.map((item, index) => {
return this.renderMarker(item, index);
});
2.
this.state.data.map((item, index) => this.renderMarker(item, index)})
3.
this.state.data.map(this.renderMarker)
If the problem persists, try printing the shape of your data and attaching it here.

Related

Updating changed value on user interface

I want my value to change on the screen when button is pressed. It does change the variable value behind the scenes but has no effect for the outdated value shown on the screen.
export default class App extends Component {
render() {
this.state = {
myVariable: 'egs'
}
const changeValue = () => {
this.state.myVariable = "CHANGED??!!"
}
return (
<View style={styles.container}>
<Text>
{this.state.myVariable}
</Text>
<Button onPress={changeValue} title="CHANGE IT"/>
</View>
);
}
}
I expect to update value to the changed one instead of outdated one.
Move state initialization outside of render as well as the changeValue method
You also cannot mutate statue directly, instead use setState()
This should work:
export default class App extends Component {
state = {
myVariable: 'egs'
}
changeValue = () => {
this.setState({myVariable:"CHANGED??!!"})
}
render() {
return (
<View style={styles.container}>
<Text>
{this.state.myVariable}
</Text>
<Button onPress={changeValue} title="CHANGE IT"/>
</View>
);
}
}
this.state.myVariable = "CHANGED??!!"
change to
this.setState({ myVariable: "CHANGED??!!" })

React-Native unable to call function

In my app i have a function outside 'export' which return a view, on click event of a button inside view another function is invoked which defined inside 'export'.
While clicking button error is received -
this4.myFunc is not a function.
screenshot attached below - error screen shot
below is my code -
export default class RosterView extends Component{
constructor(props){
super(props)
this.state={
....
}
render () {
mContext = this;
return (
<List dataArray={mContext.state.rosterList}
renderRow={(item) =>
<View style = {MainView.PlayerSelected}>
<AddPlayersToRosterList
data={item}/>
</View>
}>
</List>
);
}
isExist = (item) =>{
//My Code
return flag;
}
addRemovePlayer = (data) => {
//My Code
}
}
const AddPlayersToRosterList= ({data}) => (
(!mContext.isExist(data))?
<View style = {MainView.PlayerSelected}>
<Ripple style={MainView.PlayerAddRemoveContainer} onPress={()=> this.addRemovePlayer(data)}>
</Ripple>
</View>
)
when press button inside AddPlayersToList, this.addRemovePlayer() shows error.
please provide your help how to fix this problem.
Thanks in advance.
Hi you have many errors here. i tried to rewrite your code. try this here. and let me know if that helps. delete the whole AddPlayersToRosterList functional component that you wrote at the end. and rewrite it inside the component RosterView as a function.
The problem is, if you try to use functions that were not declared inside functional components, those components dont know the functions you are trying to call. In the case of const AddPlayersToRosterList you call the functions isExist(data) and this.addRemovePlayer(data), that were declared inside RosterView, but not inside AddPlayersToRosterList.
// add this function inside RosterView
AddPlayersToRosterList = (data) => {
(!this.isExist(data))?
<View style = {MainView.PlayerSelected}>
<Ripple
style={MainView.PlayerAddRemoveContainer}
onPress={() => this.addRemovePlayer(data)}>
</Ripple>
</View>
}
render (){
var mContext = this;
return (
<List dataArray={mContext.state.rosterList}
renderRow={(item) =>
<View style = {MainView.PlayerSelected}>
{this.AddPlayersToRosterList(item)// make sure you call the function here}
</View>
}>
</List>
);
}
you could just pass as props the functions you need to your functional component without delete anything. but it would be cost more memory and compution power that you probably need depending of how many props you want to pass.
const AddPlayersToRosterList= ({data, isExist, mContext, addRemovePlayer}) => (
(!mContext.isExist(data))?
<View style = {MainView.PlayerSelected}>
<Ripple
style={MainView.PlayerAddRemoveContainer}
onPress={()=> this.addRemovePlayer(data)}
>
</Ripple>
</View>
)
and in your render method
render () {
mContext = this;
return (
<List dataArray={mContext.state.rosterList}
renderRow={(item) =>
<View style = {MainView.PlayerSelected}>
<AddPlayersToRosterList
data={item}
isExist={this.isExist}
mContext={mContext}
addRemovePlayer={this.addRemovePlayer}
/>
</View>
}>
</List>
);
}

React Native Make State Change From different component

I am using react native and I have a situation where I navigate to a new component using react navigation v2 stack navigator. The user then presses an option and goes back to the original screen they were at with updated information.
My question is how do change the state of the previous screen so it shows the information the user selected?
ShowFruitPage.js
This page shows a list of fruits that the user picked.
export default class ShowFruitPage extends Component{
constructor(){
super();
this.state = {
List: [{Fruit: apple}]
}
}
render(){
return(
<View style={styles.ViewStyle}>
<FlatList
data={this.state.List}
renderItem={({item}) =>
<TouchableNativeFeedback
background={TouchableNativeFeedback.Ripple('grey')}
onPress={() => this.props.navigation.navigate('AddFruit',
{
List: this.state.List
})}
<View style={styles.ListView}>
<Text>{item.Fruit}</Text>
</View>
</TouchableNativeFeedback>
}
/>
</View>
)
}
}
AddFruit.js
This page shows a list of available fruits the user can pick.
When the user picks from this list I want to update the list on the ShowFruitPage.
export default class AddFruit extends Component{
constructor(){
super();
this.state = {
FruitList: [{Fruit:orange}, {Fruit: pear}]
}
this.pickFruit = this.pickFruit.bind(this);
}
pickFruit(Fruit){
//Add the picked fruit to the ShowFruitPage state List
//Then Navigate back to ShowFruitPage
this.props.navigation.navigate('ShowFruitPage')
}
render(){
return(
<View style={styles.ViewStyle}>
<FlatList
data={this.state.FruitList}
renderItem={({item}) =>
<TouchableNativeFeedback
background={TouchableNativeFeedback.Ripple('grey')}
onPress={() => this.pickFruit(item)}
<View style={styles.ListView}>
<Text>{item.Fruit}</Text>
</View>
</TouchableNativeFeedback>
}
/>
</View>
)
}
}
Just as you did in ShowFruitPage.js with List, you could navigate back with some state, i.e.
this.props.navigation.navigate('ShowFruitPage', { Fruit });
to make { Fruit } available on navigation.state.params when you navigate back to ShowFruitPage.
Another possibility (I think) is to provide a callback when you navigate to AddFruit that can set the data on the ShowFruitPage allowing you to then just call navigation.goBack():
setFruit = fruit => {
this.setState({ FruitList: [...this.state.FruitList, fruit] });
}
this.props.navigation.navigate('AddFruit', { setFruit: this.setFruit });
And then:
pickFruit(Fruit){
const { navigation } = this.props;
navigation.state.params.setFruit(Fruit);
navigation.goBack();
}
An alternative and heavier solution, would be to implement some state management such as redux so that the data becomes independent of the individual page components.

How to properly use mapDispatchToProps function in sub component?

I'm making simple Todo Application using React Native + Redux following Youtube.
Adding Todo works well. so I took next step, trying to deleting todo got problem. The Video is little bit old, so the version and platform(Mine is Android) is different. so the way of it little different... (ES5/ES6 etc.)
Anyway... I want to send action to dispatcher using mapDispatchToProps's function, onDeleteTodo, but it's not working.
First I tried to connect the component to store, so Added line TodoItem = connect(mapStateToProps, mapDispatchToProps)(TodoItem);. but the error still left.
Something wrong... but I can't find, How can I fix it?
Thanks in advance... below is my code.
import React, {Component} from 'react';
import {
StyleSheet,
Text,
View,
TextInput,
ScrollView,
TouchableOpacity
} from 'react-native';
import {connect} from 'react-redux';
import {addTodo, deleteTodo} from '../actions';
class TodoItem extends Component {
render() {
return (
// ***************************************
// Below line (onPress prop) is problem.
// when I trying to save todo,
// Error "undefined is not a function (evaluating 'this.props.onDeleteTodo(this.props.id)')
<TouchableOpacity onPress={this.props.onDeleteTodo(this.props.id)}>
<View style={styles.todoContainer}>
<Text style={styles.todoText}>
{this.props.text}
</Text>
</View>
</TouchableOpacity>
)
}
}
TodoItem = connect(
mapStateToProps,
mapDispatchToProps
)(TodoItem);
class Main extends Component {
constructor(props) {
super(props);
this.state = {
newTodoText: ""
}
}
render() {
var renderTodos = () => {
return this.props.todos.map((todo) => {
return (
<TodoItem text={todo.text} key={todo.id} id={todo.id}/>
)
})
};
return (
<View style={styles.wrapper}>
<View style={styles.topBar}>
<Text style={styles.title}>
To-Do List
</Text>
</View>
<View style={styles.inputWrapper}>
<TextInput
onChange={(event) => {
this.setState({
newTodoText: event.nativeEvent.text
});
}}
value={this.state.newTodoText}
returnKeyType="done"
placeholder="New Todo"
onSubmitEditing={
() => {
if(this.state.newTodoText && this.state.newTodoText != ''){
this.props.onAddTodo(this.state.newTodoText);
this.setState({
newTodoText: ''
});
}
}
}
underlineColorAndroid='transparent'
style={styles.input}/>
</View>
<ScrollView
automaticallyAdjustContentInsets={false}>
{renderTodos()}
</ScrollView>
</View>
);
}
}
const mapStateToProps = (state) => {
return {
todos: state.todos
}
};
const mapDispatchToProps = (dispatch) => {
return {
onAddTodo: (todo) => {
dispatch(addTodo(todo))
},
onDeleteTodo: (id) => {
dispatch(deleteTodo(id))
}
}
};
Main = connect(
mapStateToProps,
mapDispatchToProps
)(Main);
export default Main
If you write yoru code like this onPress={ this.props.onDeleteTodo(this.props.id) } then you are passing to the onPress property anything that is returned by the function this.props.onDeleteTodo. In other words, this.props.onDeleteTodo is executed when the component is rendering.
If you want to pass this function (and not it's returned value) then you need to write onPress={ this.props.onDeleteTodo.bind(this, this.props.id) }. This way you are passing this function with this as a context and this.props.id as it's first argument. More about this method here: Use of the JavaScript 'bind' method
I found the solution... but I don't know why it works.
change prop to callback function
onPress={this.props.onDeleteTodo(this.props.id)}
==>
onPress={ () => { this.props.onDeleteTodo(this.props.id) } }
: Is onPress prop only receive callback function? I don't know.
Move connect statement to below of const mapStateToProps and mapDispatchToProps
: Is const ... variable only can reference below its declaration? I don't know also.
I don't really know If I've understood your code...
By the way, if you are importing any function from somewhere, I think that you don't have to use dispatch method, since deleteTodo is not a property method.
Try again without dispatch(), moreover, try to call directly deleteTodo() method.
EDIT: in onPress event write this -> onPress={() => deleteTodo(this.props.id)}
It should call the method onces the event is triggered
And let me know if it works!

React Native ES6 Syntax: Undefined is not an object

I tried out the following example (Fading Hearts) from React Native Playground:
https://rnplay.org/apps/CkBOBQ
The example is written in createClass syntax. I converted the same to ES6 syntax where I used classes and methods. The app compiles and opens properly but when I tap on the app, it throws this error:
Undefined is not an object (evaluating '_this3.state.hearts[i].right')
There is also a warning:
Warning: setState(...): Cannot update during an existing state transition
Part of the code is shown below. If I remove the line onComplete={this.removeHeart(v.id)}, there is no error or warning. But this only because we are not properly destroying the heart object. Could someone point out what I'm doing wrong?
class App extends Component {
constructor(props) {
super(props);
this.state = {hearts: []}
this.addHeart = this.addHeart.bind(this);
this.removeHeart = this.removeHeart.bind(this);
}
addHeart() {
startCount += 1;
this.state.hearts.push({
id: startCount,
right: getRandomNumber(50, 150)
});
this.setState(this.state);
}
removeHeart(v) {
var index = this.state.hearts.findIndex((heart) => heart.id === v);
this.state.hearts.splice(index, 1);
this.setState(this.state);
}
render() {
return (
<View style={styles.container}>
<TouchableWithoutFeedback style={styles.container} onPress={this.addHeart}>
<View style={styles.container}>
{
this.state.hearts.map((v, i) =>
<AnimatedHeart
key={v.id}
onComplete={this.removeHeart(v.id)}
style={{right: this.state.hearts[i].right}}
/>
, this)
}
</View>
</TouchableWithoutFeedback>
<Text style={styles.message}>Tap anywhere to see hearts!</Text>
</View>
);
}
}
you are actually invoking the function with your current code. You need to give a function reference to trigger and not actually invoke the function. meaning
onComplete={this.removeHeart(v.id)}
should be this
onComplete={() => this.removeHeart(v.id)}
when the render cycle goes off it calls the removeHeart function which ends up calling setState while the render is happening cannot set state in a transition
You are passing argument to removeHeart in the wrong manner
<View style={styles.container}>
{
this.state.hearts.map((v, i) =>
<AnimatedHeart
key={v.id}
onComplete={this.removeHeart.bind(this,v.id)}
style={{right: this.state.hearts[i].right}}
/>)
}
</View>
and there is no need to pass this to map when you use the arrow function notation

Resources