Want to pass data to other component - ListView - ios

I have added and imported the sample data. I want to list out data from this file in a list view and I'm passing the data to the Row Component for RenderRow. But getting error saying
Row(...): A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object.
import React, { Component } from 'react';
import { AppRegistry, View, ListView, Text, StyleSheet } from 'react-native';
import Row from './app/Row';
import data from './app/Data';
export default class ListViewDemo extends Component {
constructor(props) {
super(props);
const rowHasChanged = (r1, r2) => r1 !== r2
const ds = new ListView.DataSource({rowHasChanged});
this.state = {
dataSource: ds.cloneWithRows(data),
};
render() {
return (
<ListView
dataSource={this.state.dataSource}
renderRow={(data) => <Row {...data} />} // Getting error here
/>
);
}
}
AppRegistry.registerComponent('DemoApp',() => ListViewDemo)
These my sample Data.js You can check the data here.
export default data = [
{...}, {...}
];
Row.js:
const Row = (props) => {
<View Style={styles.container}>
<Image source={{ uri: props.picture.large}} />
<Text >
{`${props.name.first} ${props.name.last}`}
</Text>
</View>
}
What would be the problem?

ES6 only returns when there is no explicit blocks:
const cb = (param) => param * 2;
You should explicitly return:
const Row = (props) => {
return (
<View Style={styles.container}>
<Image source={{ uri: props.picture.large}} />
<Text >
{`${props.name.first} ${props.name.last}`}
</Text>
</View>
);
}
Check this answer for further explanation.

Change this Line to
renderRow={(data) => <Row {...data} />}
To This
renderRow={(data) =><Row {...this.props} />}
This may help you to get props in the row Component

Related

React Native NOT rendering data from database on IOS

I have problem with render data on IOS Simulator. Render is work properly on website, but on IOS I still got stuck on "Loading.." text.
Here is my code:
import React from 'react'
import { useState } from 'react';
import { useEffect } from 'react';
import { SafeAreaView, Text, View, StyleSheet, Image, Alert } from 'react-native';
import { Card } from 'react-native-paper'
import firebase from 'firebase'
import Button from '../components/Button'
import Background from '../components/Background'
import TopBar from '../components/TopBar'
export default function HomeScreen({ navigation }) {
const [data, setData] = useState([])
const sampleData = [{id:0, title:"One"}, {id:1, title: "Two"}]
useEffect(() =>
{
const donorsData = [];
firebase.database()
.ref("testdb")
.orderByChild("isDonor")
.equalTo(true)
.once("value")
.then((results) => {
results.forEach((snapshot) => {
donorsData.push(snapshot.val());
});
setData(donorsData);
});
}, [])
const card = data.length > 0
? data.map(item =>
{
return <Card key={item.uid} style={{ marginBottom: 20, borderRadius: 10, }}>
<Text>{item.name}</Text>
<Text>{item.description}</Text>
<Image src={item.photo}></Image>
</Card>
})
: <Text>Loading...</Text>
return (
<View style={styles.container}>
{card}
</View>
);
}
On website is everything ok Website Screen
But on IOS Simulator I got only Loading
IOS Screen
I tried a lot of solutions found here, but no one works with this case. I think is probably because iOS doesn't have data? When I put console log at to top of return, I got nothing.
This might be a race condition error. You shouldn't rely on the data being fetched within 1500ms.
If that doesn't work. Make sure your result from firebase is correct.
Maybe something like this?
const [data, setData] = useState([])
const fetchDonorData = () => {
firebase.database()
.ref("testdb")
.orderByChild("isDonor")
.equalTo(true)
.once("value")
.then((results) => {
console.log({result}) //Make sure the data looks the way you want it
const mappedResult = results?.map(snapshot => snapshot.val())
setData(mappedResult)
})
}
useEffect(() => {
fetchDonorData()
}, [])
const renderItem = ({item}) =>
<Card style={{ marginBottom: 20, borderRadius: 10, }}>
<Text>{item.name}</Text>
<Text>{item.description}</Text>
<Image src={item.photo}></Image>
</Card>
return (
<View style={styles.container}>
<FlatList
data={data}
renderItem={renderItem}
keyExtractor={({item}) => item.uid}
ListEmptyComponent={<Text>Loading...</Text>}
/>
</View>
)

Unable to display fetched data in react native firebase using this.state.data.map()

I have been battling with the display of database item on my page using this.state.noteArray.map(val, key). I intend to display each value with a delete button to remove it from the page.
import React, { Component } from 'react';
import {
View,
Text,
StyleSheet,
TextInput,
ScrollView,
TouchableOpacity
} from 'react-native';
import firebase from 'firebase';
// Initialize Firebase
const config = {
apiKey: "XXXXXXXXXXXXXXX",
authDomain: "XXXXXXXXXXXXXXXXXXXXXX",
databaseURL: "XXXXXXXXXXXXXXXXXXXXXXXX",
projectId: "XXXXXXXXXXXXXXXXXXXXXX",
storageBucket: "",
messagingSenderId: "XXXXXXXXXXXXXXXXXXXX"
};
firebase.initializeApp(config);
export default class Main extends Component {
constructor(props){
super(props);
this.state = {
noteArray: [],
noteText: '',
};
this.addNote = this.addNote.bind(this);
}
componentDidMount(){
firebase.database()
.ref()
.child("todo")
.once("value", snapshot => {
const data = snapshot.val()
if (snapshot.val()){
const initNoteArray = [];
Object
.keys(data)
.forEach(noteText => initNoteArray.push(data[noteText]));
this.setState({
noteArray: initNoteArray
});
}
});
firebase.database()
.ref()
.child("todo")
.on("child_added", snapshot => {
const data = snapshot.val();
if (data){
this.setState(prevState => ({
noteArray: [data, ...prevState.noteArray]
}))
console.log(this.state.noteArray);
}
})
}
addNote(){
// firebase function here to send to the database
if (!this.state.noteText) return;
var d = new Date();
const newNote = firebase.database().ref()
.child("todo")
.push ({
'date':d.getFullYear()+
"/"+(d.getMonth()+1) +
"/"+ d.getDate(),
'note': this.state.noteText
});
newNote.set(this.state.noteText, () => this.setState({noteText: ''}))
}
render() {
let notes = this.state.noteArray.map((val, key)=>{
return
(<View key={key} keyval={key} val={val} style={styles.note}>
<Text style={styles.noteText}>{this.state.val.date}</Text>
<Text style={styles.noteText}>{this.state.val.note}</Text>
<TouchableOpacity onPress={this.state.deleteMethod} style={styles.noteDelete}>
<Text deleteMethod={()=>this.deleteNote(key)} style={styles.noteDeleteText}>D</Text>
</TouchableOpacity>
</View>)
});
return (
<View style={styles.container}>
<View style={styles.header}>
<Text style={styles.headerText}>Todo App</Text>
</View>
<ScrollView style={styles.scrollContainer}>
{notes}
</ScrollView>
<View style={styles.footer}>
<TextInput
style={styles.textInput}
placeholder='>note'
onChangeText={(noteText)=> this.setState({noteText})}
value={this.state.noteText}
placeholderTextColor='white'
underlineColorAndroid='transparent'>
</TextInput>
</View>
<TouchableOpacity onPress={ this.addNote } style={styles.addButton}>
<Text style={styles.addButtonText}>+</Text>
</TouchableOpacity>
</View>
);
}
deleteNote(key){
this.state.noteArray.splice(key, 1);
this.setState({noteArray: this.state.noteArray});
}
}
There is no warning or error, but it is not displaying anything. I will appreciate if there is any help and inline comment to understand the process for the next time, I am a newbie, trying to master the code for future similar projects. All I care to know is the basic understanding of the CRUD and search using React native firebase. Thank you so much
If I correctly understand you need a proper way to display your data. Since noteArray is an array, there's nothing easier than a FlatList, which is scrollable by itself.
So, in your render method:
render() {
return (
<View style={styles.container}>
<FlatList
data={this.state.noteArray} // Here is where you pass your array of data
renderItem={this.renderItem} // Here is how to display each item of your data array
ListHeaderComponent={this.renderHeader}
ListFooterComponent={this.renderFooter}
/>
</View>
);
}
Where:
renderHeader = () => {
return (
<View style={styles.header}>
<Text style={styles.headerText}>Todo App</Text>
</View>
)
}
renderFooter = () => {
return (
<View>
<View style={styles.footer}>
<TextInput
style={styles.textInput}
placeholder='>note'
onChangeText={(noteText)=> this.setState({noteText})}
value={this.state.noteText}
placeholderTextColor='white'
underlineColorAndroid='transparent'>
</TextInput>
</View>
<TouchableOpacity onPress={ this.addNote } style={styles.addButton}>
<Text style={styles.addButtonText}>+</Text>
</TouchableOpacity>
</View>
)
}
renderItem = ({ item, index }) => {
return (
<View key={index} style={styles.note}>
<Text style={styles.noteText}>{item.date}</Text>
<Text style={styles.noteText}>{item.note}</Text>
<TouchableOpacity onPress={this.state.deleteMethod} style={styles.noteDelete}>
<Text deleteMethod={()=>this.deleteNote(index)} style={styles.noteDeleteText}>D</Text>
</TouchableOpacity>
</View>
)
}
Thanks for your support. I have reviewed my code and it is working perfectly as I want. I will love to post it here in case someone else needs to work or learn about it. I used array.map() function to iterate over the items.
import React, { Component } from 'react';
import {
View,
Text,
StyleSheet,
TextInput,
ScrollView,
TouchableOpacity
} from 'react-native';
import Note from './Note';
import firebase from 'firebase';
// Initialize Firebase
const config = {
apiKey: "XXXXXXXXXXXXXXXXXXXXXXXXXX",
authDomain: "XXXXXXXXXXXXXXXXXXXXXX",
databaseURL: "XXXXXXXXXXXXXXXXXXXXXXXX",
projectId: "XXXXXXXXXXXXXXXXXXXXXXXXX",
storageBucket: "",
messagingSenderId: "XXXXXXXXXXXXXXXX"
};
firebase.initializeApp(config);
export default class Main extends Component {
constructor(props){
super(props);
this.state = {
noteArray: [],
noteText: '',
};
this.addNote = this.addNote.bind(this);
}
componentDidMount(){
firebase.database()
.ref()
.child("todo")
.once("value", snapshot => {
const data = snapshot.val()
if (snapshot.val()){
const initNoteArray = [];
Object
.keys(data)
.forEach(noteText => initNoteArray.push(data[noteText]));
this.setState({
noteArray: initNoteArray
});
}
});
firebase.database()
.ref()
.child("todo")
.on("child_added", snapshot => {
const data = snapshot.val();
if (data){
this.setState(prevState => ({
noteArray: [data, ...prevState.noteArray]
}))
console.log(this.state.noteArray);
}
})
}
addNote(){
// firebase function here to send to the database
if (!this.state.noteText) return;
var d = new Date();
const newNote = firebase.database().ref()
.child("todo")
.push ();
newNote.set({
'date':d.getFullYear()+
"/"+(d.getMonth()+1) +
"/"+ d.getDate(),
'note': this.state.noteText
});
this.setState({noteText:''});
}
render() {
let notes = this.state.noteArray.map((val, key)=>{
return <Note key={key} keyval={key} val={val}
deleteMethod={()=>this.deleteNote(key)}/>
});
return (
<View style={styles.container}>
<View style={styles.header}>
<Text style={styles.headerText}>Todo App</Text>
</View>
<ScrollView style={styles.scrollContainer}>
{notes}
</ScrollView>
<View style={styles.footer}>
<TextInput
style={styles.textInput}
placeholder='>note'
onChangeText={(noteText)=> this.setState({noteText})}
value={this.state.noteText}
placeholderTextColor='white'
underlineColorAndroid='transparent'>
</TextInput>
</View>
<TouchableOpacity onPress={ this.addNote } style={styles.addButton}>
<Text style={styles.addButtonText}>+</Text>
</TouchableOpacity>
</View>
);
}
deleteNote(key){
this.state.noteArray.splice(key, 1);
this.setState({noteArray: this.state.noteArray});
}
}
I have another .js component named Note.js for display template. This was included in the Main.js and was reference just after the render.
import React, { Component } from 'react';
import {
View,
Text,
StyleSheet,
TouchableOpacity,
} from 'react-native';
export default class Note extends Component {
render() {
return (
<View key={this.props.keyval} style={styles.note}>
<Text style={styles.noteText}>{this.props.val.date}</Text>
<Text style={styles.noteText}>{this.props.val.note}</Text>
<TouchableOpacity onPress={this.props.deleteMethod} style={styles.noteDelete}>
<Text style={styles.noteDeleteText}>D</Text>
</TouchableOpacity>
</View>
);
}
}

differents buttons, differents images? react native

I'm a student and I developing a mobile app with React Native.
My target is this image:
(https://cdn.discordapp.com/attachments/403580119714889736/407172407049060352/Apercu_bingo_2_choisir_invites.jpg)
I could write the code with independent buttons, the problem appears when I want to add different images to each button. (I'm waiting for the back dev to create a boucle to add all the images with the shortest code possible (looking forward for some loop ideas ;) ).
import React, {Component} from 'react';
import Button from 'react-native-button';
import
{
AppRegistry,
StyleSheet,
View,
Text,
TouchableHighlight,
Alert,
Image,
ScrollView,
TouchableWithoutFeedback
}
from 'react-native';
import styles from './Styles';
class ToggleButton extends React.Component {
render() {
return (
<View style={styles.cont2}>
<TouchableHighlight style={styles.bubblechoice} onPress={this.props.onPress}>
<View style={[styles.overlay, this.props.selected ? {backgroundColor: '#3C1088'} : {}]}>
<Image style={styles.bubblechoice} source={require('./photo1.jpg')}/>
</View>
</TouchableHighlight>
</View>
);
}
}
export default class MyComponent extends Component
{
constructor(props) {
super(props);
this.state = {
inv1: false,
inv2: false,
};
}
updateChoice(type) {
let newState = {...this.state};
newState[type] = !newState[type];
this.setState(newState);
}
render() {
return (
<View style={styles.containerinvite}>
<ScrollView contentContainerStyle={styles.list}>
<ToggleButton label='inv1' onPress={() => { this.updateChoice('inv1') } } selected={this.state.inv1}/>
<ToggleButton label='inv2' onPress={() => { this.updateChoice('inv2') } } selected={this.state.inv2}/>
<TouchableWithoutFeedback
onPress={() => {Alert.alert('OK');}}>
<View style={styles.button}>
<Text style={styles.buttonText}>ok</Text>
</View>
</TouchableWithoutFeedback>
</View>
);
}
onPress1 = () => {
this.setState({
inv1: !this.state.inv1
});
}
onPress2 = () => {
this.setState({
inv2: !this.state.inv2
});
}
}
The result that I have is:
https://scontent-cdt1-1.xx.fbcdn.net/v/t35.0-12/28580783_10216099091730046_1132055272_o.png?oh=fdb33bbe2b82f29cac1d80b8e25f269e&oe=5A9B2488&dl=1, https://www.facebook.com/
The thing is that the View that changes the status color can't be without children, so I can't just change the image from there. I tried different options but I'm still can manage different photos with independents buttons.
From your parent component you should pass your photos to the child component and use that prop for your source instead of
<Image style={styles.bubblechoice} source={require('./photo1.jpg')}/> =>> This is wrong.
<Image style={styles.bubblechoice} source={require(photoUrls)}/> =>> It should be like this.
If you have further questions about it do not hesitate to ask.

Populating React-Native ListView from JSON Data

React-Native amateur here, I've written a php api to retrieve data from a MySQL server, and I need to put this into a ListView to display on an app.
The code for showing this is:
constructor(props) {
super(props);
var ds = new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2
});
this.state = {
dataSource: ds.cloneWithRows(this.props.response)
};
}
renderRow(rowData) {
return (
<View style={styles.row}>
<Text>{response}</Text>
</View>
)
}
render() {
return {
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderRow.bind(this)}/>
);
}
}
And the API json return is as follows:
[{"barcode":"50201600","name":"Cadbury's Creme
Egg","tescoPrice":"1","sainsburysPrice":"1","asdaPrice":"1"},
{"barcode":"5034660520191","name":"Cadburys Twirl 4
Pack","tescoPrice":"1","sainsburysPrice":"1","asdaPrice":"1"}]
The error I get is:Objects are not valid as a React child (found: object with keys {barcode, name, tescoPrice, sainsburysPrice, asdaPrice}). If you meant to render a collection of children, use an array instead. Check the render method of 'Text'
Any ideas?
Cheers
From the error i see, you need to change from:
renderRow(rowData) {
return (
<View style={styles.row}>
<Text>{response}</Text>
</View>
)
}
into something like:
renderRow(rowData) {
return (
<View style={styles.row}>
<Text>{rowData.name}</Text>
</View>
)
}

React Native Element Type is invalid Error While using ActivityIndicatorIOS

I have begun to develop a book-searching application using React and Google Books API. However, I have run into an error where my simulator reads:
Element Type is invalid: expected a string (for built-in components) or
a class/function (for composite components) but got: undefined. Check
the render method of 'BookList'.
Given that I am fairly new to React, I was hoping someone might be able to point out the error(s) in my code below. I have noted the place where I think there may be an error. Thanks!
class BookList extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoading: true,
dataSource: new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2
})
};
}
componentDidMount() {
this.fetchData();
}
fetchData() {
fetch(REQUEST_URL[0])
.then((response) => response.json())
.then((responseData) => {
this.setState({
dataSource: this.state.dataSource.cloneWithRows(responseData.items),
isLoading: false
});
})
.done();
}
render() {
if (this.state.isLoading) {
return this.renderLoadingView();
}
return (
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderBook.bind(this)}
style={styles.listView}
/>
);
}
// *** adding this function (and using it) began to cause issues ****
renderLoadingView() {
return (
<View style={styles.loading}>
<ActivityIndicatorIOS
size='large'/>
<Text>
Loading books...
</Text>
</View>
);
}
renderBook(book) {
return (
<TouchableHighlight>
<View>
<View style={styles.container}>
<Image
source={{uri: book.volumeInfo.imageLinks.thumbnail}}
style={styles.thumbnail} />
<View style={styles.rightContainer}>
<Text style={styles.title}>{book.volumeInfo.title}</Text>
<Text style={styles.author}>{book.volumeInfo.authors}</Text>
<Text style={styles.price}>{'Lowest Available Price: ' + book.volumeInfo.price}</Text>
</View>
</View>
<View style={styles.separator} />
</View>
</TouchableHighlight>
);
}
}
var REQUEST_URL = ['https://www.googleapis.com/books/v1/volumes?q=subject:fiction'];
ActivityIndicatorIOS is depreciated use ActivityIndicator instead.

Resources