React native: "Invariant Violation: Objects are not valid as a React child" - javascript

Have googled the entire day and found similar problems but no answers that fixes my problem. It seems as though the "timeLeft" put as the "until" under countdown is an object, even though the log (typeof timeLeft) says that it's a number (as it's supposed to be).
I get errormessage:
Invariant Violation: 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.
render() {
return (
<View style={styles.container}>
<ScrollView>
<View>
{
this.state.auctions.map(async (auctionObject, index) => {
var timeLeft = await this.getTimeLeft(auctionObject.expiration);
console.log(JSON.stringify(timeLeft) + typeof timeLeft)
return <View style={styles.auctionObject} key={index + 'a'}>
<Text key={index + 'b'} onPress={() => this._renderObjectPage(auctionObject)}>
TITLE: {auctionObject.title} {"\n"}
HIGHEST BID: {auctionObject.highestBid} {"\n"}
NUMBER OF LIKES:{auctionObject.numberOfLikes}
</Text>
<CountDown key={index + 'c'}
until={timeLeft}
timetoShow={('H', 'M', 'S')}
size={12}
/>
</View>
}
)
}
</View>
</ScrollView>
Thank you

The problem is that your render function is outputting a list of Promise objects (which isn't valid react code):
this.state.auctions.map(async (auctionObject, index) => {
var timeLeft = await this.getTimeLeft(auctionObject.expiration);
Question: Are you sure that the getTimeLeft operation needs to be async? If so then this operation will need to be done outside of the render function (possibly in componentDidMount or componentDidUpdate).
If you can change getTimeLeft to be synchronous, it will work:
this.state.auctions.map((auctionObject, index) => {
var timeLeft = this.getTimeLeft(auctionObject.expiration);

Related

How to solve: Objects are not valid as a React child (found: object with keys {_U, _V, _W, _X}?

Im trying to map my state , but it allways returns me this error, someone knows how to solve it ?
useEffect(() => {
if (mounted && userForm.length > 0) {
console.log(userForm, 'campos:', userForm.fields);
return;
} else {
setuserForm(JSON.parse(route.params.paramKey));
console.log(userForm);
}
}, [userForm]);
return (
<SafeAreaView style={{flex: 1}}>
<View style={styles.container}>
<Text style={styles.textStyle}>COLLECTION :</Text>
{userForm.length > 0 ? (
userForm.map((item) => (
<Text key={uuid.v4()}>{item.fields}</Text>
))
) : (
<Text key={uuid.v4()}> Loading ...</Text>
)}
</View>
</SafeAreaView>
);
};
what I'm trying to do is render all my fields and then handle the following types.
If I understand you correctly, you are trying to render item.field as node. However, seems that this is an array, so you need to map it one more time.
For example, if it contains strings it might looks like this:
<Text key={uuid.v4()}>{item.fields?.concat('')}</Text>
In case filds contains objects you have to map it to the new component, like this:
<Text key={uuid.v4()}>{item.fields?.map((field, i)=> <div key={i}>{field.someProp}</div>}</Text>
In case you don't know what is inside the fields, check the Network tab in the ChromeDeveloperTools (F12) or use JSON.stringify

useState Hook not taking data [duplicate]

This question already has answers here:
The useState set method is not reflecting a change immediately
(15 answers)
Closed 1 year ago.
I am trying to set the state to the props I get from Redux. I have an array, props.feed, displaying an array on the console. But setting my state to this array doesn't change the state, that remains undefined, and it's not rendering my Flatlist because the data is undefined.
If I log props.feed it works. If I log my state posts after using setPosts the hook doesn't take the data.
function FeedScreen(props) {
const [posts, setPosts] = useState([]);
const imageWidth = Math.floor(useWindowDimensions().width);
useEffect(() => {
if (
props.usersFollowingLoaded == props.following.length &&
props.following.length != 0
) {
props.feed.sort((x, y) => {
return x.creation - y.creation;
});
console.log("Props Feed", props.feed);
setPosts(props.feed);
console.log("Posts of friends", posts);
}
}, [props.usersFollowingLoaded, props.feed]);
return (
<View style={styles.container}>
<View style={styles.containerGallery}>
<FlatList
numColumns={1}
data={posts}
horizontal={false}
renderItem={({ item }) => (
<View style={styles.containerImage}>
<Text style={styles.container}>
{item.user.name}
</Text>
<Image
style={styles.image}
source={{ uri: item.downloadURL }}
/>
<Text
onPress={() =>
props.navigation.navigate("Comments", {
postId: item.id,
uid: item.user.uid,
})
}
>
View comments...
</Text>
</View>
)}
/>
</View>
</View>
);
}
Here is the console.
You are misunderstanding on how React.useState (and rendering) works.
When you call setPosts, it doesn't immediately set posts to the value. It tells React "I want posts to equal <this value>" and React will re-render your component later with the updated state variable.
As for your FlatList not rendering the list, that's another issue. Is it a component you wrote yourself?

Conditional statement inside JSX in react native?

I want to set my state inside JSX expression and show my component if the condition is true. How can i achieve that? i tried this this first :
{(currenMonth !== item.orderDate)
&& (setCurrentMonth(item.orderDate) && <Item name={getMonthFromString(item.orderDate)} active />)
}
In a second solution i've created this function :
const ProductsList = () => {
const [currenMonth, setCurrenMonth] = useState('');
const renderItem = (month) => {
if (currenMonth !== month) {
setCurrenMonth(month);
return <Item name={getMonthFromString(month)} active />;
}
return null;
};
return(
<View style={styles.container}>
<FlatList
data={products}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item }) => {
return (
<View>
{ renderItem(item.orderDate) }
</View>
);
}}
/>
</View>
);
}
But i'm getting an Error [Unhandled promise rejection: Invariant Violation: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.]
There are two ways: practically the way you're doing it inside JSX and then a separate rendering function. I'll recommend the latter. But mentioned, render is not part of setting state. So you actually have two separate problems.
...
const renderMonthItem = () => (
(<yourConditionals> ? <Item ... /> : null;
)
...
return (
<View> ...
{ renderMonthItem() }
... </View>
);

React Native: filtering props?

I created a basic component such as:
export default (props) => (
<TouchableOpacity {...props} style={styles.button}>
{props.title && <Text style={styles.text}>{props.title}</Text>}
{props.icon && <Icon name={props.icon} />}
</TouchableOpacity>
);
I can then call it with <Component title="Home" icon="home" /> for instance.
The problem is that passing {...props} to TouchableOpacity generate errors because it does not recognize title nor icon properly.
For instance:
JSON value 'Home' of type NSString cannot be converted to...
Is there a way to filter props so that I only pass valid ones for TouchableOpacity?
Transferring Props
Sometimes it's fragile and tedious to pass every property along. In that case you can use destructuring assignment with rest properties to extract a set of unknown properties.
List out all the properties that you would like to consume, followed by ...other.
var { checked, ...other } = props;
This ensures that you pass down all the props EXCEPT the ones you're
consuming yourself.
function FancyCheckbox(props) {
var { checked, ...other } = props;
var fancyClass = checked ? 'FancyChecked' : 'FancyUnchecked';
// `other` contains { onClick: console.log } but not the checked property
return (
<div {...other} className={fancyClass} />
);
}
ReactDOM.render(
<FancyCheckbox checked={true} onClick={console.log.bind(console)}>
Hello world!
</FancyCheckbox>,
document.getElementById('example')
);
Like Paul Mcloughlin, I would recommend using object destructuring along with a rest parameter. You can destructure your props object directly in your function parameters like so:
({title, icon, ...remainingProps}) => (...)
This extracts the title and icon props from your props object and passes the rest as remainingProps.
Your complete component would be:
export default ({title, icon, ...remainingProps}) => (
<TouchableOpacity {...remainingProps} style={styles.button}>
{title && <Text style={styles.text}>{title}</Text>}
{icon && <Icon name={icon} />}
</TouchableOpacity>
);

AsyncStorage React Native save an Array

I tried saving an array, I tried to follow the documentation but failed miserably. How should I write it so that it doesn't give me various warnings and errors.
Errors :
got an [Object Object] when I try to set the item
Got an object instead of an array
Attempted to assign to read only property
expected a string, got an array
Here is the code : App.js
import React from "react";
import {
StyleSheet,
Text,
View,
TextInput,
ScrollView,
TouchableOpacity,
KeyboardAvoidingView,
AsyncStorage
} from "react-native";
import Note from "./app/components/note";
export default class App extends React.Component {
state = {
noteArray: [],
noteText: ""
};
render() {
let notes = this.state.noteArray.map((val, key) => {
return (
<Note
key={key}
keyval={key}
val={val}
deleteMethod={() => this.deleteNote(key)}
/>
);
});
return (
<KeyboardAvoidingView behavior="padding" style={styles.container}>
<View style={styles.header}>
<Text style={styles.headerText}>Tasker</Text>
</View>
<ScrollView style={styles.scrollContainer}>{notes}</ScrollView>
<View style={styles.footer}>
<TouchableOpacity
onPress={this.addNote.bind(this)}
style={styles.addButton}
>
<Text style={styles.addButtonText}>+</Text>
</TouchableOpacity>
<TextInput
style={styles.textInput}
placeholder="Enter Task..."
placeholderTextColor="white"
underlinedColorAndroid="transparent"
onChangeText={noteText => this.setState({ noteText })}
value={this.state.noteText}
/>
</View>
</KeyboardAvoidingView>
);
}
addNote() {
if (this.state.noteText) {
var d = new Date();
this.state.noteArray.push({
date:
d.getFullYear() +
"/" +
(d.getMonth() + 1) +
"/" +
d.getDate(),
note: this.state.noteText
});
this.setState({ noteArray: this.state.noteArray });
this.setState({ noteText: "" });
}
//AsyncStorage.setItem() How do I write it so no errors occur
alert({ noteArray: this.state.noteArray });
}
}
Extra Note : The Error is on Expo App on my phone both Android and iOS
Thanks in Advance!
Arrays and other objects need to be saved as strings in AsyncStorage.
AsyncStorage.setItem('arrayObjKey', JSON.stringify(myArray));
Also if you need to update the values in the array use AsyncStorage.multiMerge
From the React-Native docs:
Merges an existing key value with an input value, assuming both values are stringified JSON. Returns a Promise object.

Categories