I am new to react native and was trying to display some data into a react component (preferably cards) but for now FlatList will work. I was unable to destructure the data and display it. How should it be done?
import React,{useState,useEffect} from 'react';
import { StyleSheet,Modal, View ,Text , ScrollView, Alert} from 'react-native';
import {IconButton ,Appbar, Card, TextInput ,Button ,
} from 'react-native-paper';
import firebase from './config';
import { LogBox } from 'react-native';
LogBox.ignoreLogs(['Setting a timer']);
export default function PlantATree(){
const [modalVisible, setModalVisible] = useState(false);
const [name,setName]=useState('');
const [title, setTitle]=useState('');
const [description, setDescription]=useState('');
const [data, setmyData]=useState([])
const savePost = () =>{
firebase.database()
.ref('posts')
.push({
"id":Math.random(),
"name":name,
"title":title,
"description":description,
})
setTimeout(()=>{
Alert.alert("Your post is saved successfully :D")
},1000)
}
useEffect(()=>{
const data = firebase.database().ref("posts");
data.on("value", datasnap =>{
//console.log(Object.values(datasnap.val()));
if(datasnap.val()){
setmyData(datasnap.val());
}
})
},[]);
//console.log(data);
const src= Object.keys(data);
console.log("Hi",src);
return (
<ScrollView>
<Appbar.Header>
<Appbar.Content title="Plant a tree Initiative"/>
</Appbar.Header>
<IconButton
icon="plus"
color="crimson"
size={30}
onPress={() => setModalVisible(true)}
/>
<View style={styles.centeredView}>
{/*Modal Content Starts Here*/}
<Modal
animationType="slide"
transparent={true}
visible={modalVisible}
>
<View style={styles.centeredView}>
<ScrollView style={styles.modalView}>
<Appbar.Header style={{ padding:10}}>
<Appbar.Content title="Share your story.." />
</Appbar.Header>
<Card>
<Card.Content >
<View style={{marginLeft:0,marginRight:0,
}}>
<Card >
<Card.Content>
<TextInput
style={{}}
label="Your name...."
mode="outlined"
value={name}
onChangeText={text =>{ setName(text)}}
/>
<TextInput
style={{}}
label="Story Title...."
mode="outlined"
value={title}
onChangeText={text =>{ setTitle(text)}}
/>
<TextInput
style={styles.formcomponents}
label="Share your thoughts...."
mode="outlined"
multiline={true}
numberOfLines={8}
value={description}
onChangeText={text =>{ setDescription(text)}}
/>
</Card.Content>
</Card>
</View>
<Card>
<Button mode="contained" style={{margin:20}}
onPress={savePost}>
post
</Button>
<Button mode="contained" style={{margin:20,backgroundColor:'crimson'}} onPress={() => setModalVisible(!modalVisible)}>
close
</Button>
</Card>
</Card.Content>
</Card>
</ScrollView>
</View>
</Modal>
</View>
<View>
{/* DATA FROM FIREBASE */}
<Text>{data?.description}</Text>
</View>
</ScrollView>
)
}
const styles = StyleSheet.create({
centeredView: {
marginTop: 45,
marginBottom:45,
},
modalView: {
backgroundColor: "white",
borderRadius: 20,
marginTop:70,
marginBottom:20,
marginRight:20,
marginLeft:20,
shadowColor: "#000",
shadowOffset: {
width: 0,
height: 2
},
shadowOpacity: 0.25,
shadowRadius: 3.84,
elevation: 5
},
openButton: {
backgroundColor: "#F194FF",
borderRadius: 20,
padding: 10,
elevation: 2
},
textStyle: {
color: "white",
fontWeight: "bold",
textAlign: "center"
},
});
Data Format:
Object {
"-MQXpKu8Zh1PCVsBLquO": Object {
"description": "Good story.",
"id": 0.8842625745597491,
"name": "Subhodeep",
"title": "Story 1 ",
},
"-MQXpRXS5_6m6YTZ39e0": Object {
"description": "Good story 2.",
"id": 0.8767685757714464,
"name": "Sanjoy",
"title": "Story 2",
},
"-MQXpX7ku-41CreQ8SOP": Object {
"description": "Good story 3.
",
"id": 0.9976208307830834,
"name": "Sanchari",
"title": "Story 3",
},
Since the data from Firebase consists of multiple nodes, you'll need to iterate over the results and map each child to a new component.
I typically find that easiest by first converting the snapshot to an array (instead of an Object) when it is loaded:
useEffect(()=>{
const data = firebase.database().ref("posts");
data.on("value", datasnap =>{
let data = [];
datasnap.forEach((childsnap) => {
let val = childsnap.val();
val["$key"] = childsnap.key;
data.push(val);
})
setmyData(data);
})
},[]);
Then in the rendering code we can loop over this data array and render a component for each item:
data.map((item) => <Text id={item["$key"]}>{item.description}</Text>)
There might be some syntax errors in the rendering, but the overall flow should be clear from this.
Related
I am new to react native.
I created some custom components in project. And I pass some style to them via the props but my passing styles are not attached to that components. At the first it was working correctly but suddenly I don't know what happened that my passing styles are not working.
Here is my code:
This the page where I used my custom component and passed style to that.
function StartGameScreen(props) {
const [confirmed, setConfirmed] = useState(false);
const [selectedNumber, setSelectedNumber] = useState();
const numInputHandler = (inputText) => {
setEneteredValue(inputText.replace(/[^0-9]/g, ""));
};
const confirmInput = () => {
const chosenNumber = parseInt(enteredValue);
if (isNaN(chosenNumber) || chosenNumber <= 0 || chosenNumber > 99) {
Alert.alert(
"Invalid number!",
"Number has to be a number between 0 and 99.",
[{ text: "Okay", style: "destructive", onPress: resetInput }]
);
return;
}
setConfirmed(true);
setSelectedNumber(chosenNumber);
setEneteredValue("");
Keyboard.dismiss();
};
let confirmedOutput;
if (confirmed) {
confirmedOutput = (
<Card style={styles.summeryContainer}>
<Text>You selected</Text>
<NumberContainer>{selectedNumber}</NumberContainer>
<Button
title="START GAME"
onPress={() => {
console.log("hello" + selectedNumber);
props.onStartGame(selectedNumber);
}}
/>
</Card>
);
}
return (
<TouchableWithoutFeedback
onPress={() => {
Keyboard.dismiss();
}}
>
<View style={styles.container}>
<Text style={styles.title}>Start A New Game!</Text>
*This is where I used my custom component (<Card>).*
<Card style={styles.inputContainer}>
<Text>select a number</Text>
<Input
style={styles.input}
blurOnSubmit
autoCapatilize="none"
autoCorrect={false}
keyboardType="number-pad"
maxLength={2}
onChangeText={numInputHandler}
value={enteredValue}
/>
<View style={styles.buttonCon}>
<View style={styles.button}>
<Button
title="Reset"
color={Colors.accent}
onPress={resetInput}
/>
</View>
<View style={styles.button}>
<Button
title="Confirm"
color={Colors.primary}
onPress={confirmInput}
/>
</View>
</View>
</Card>
{confirmedOutput}
</View>
</TouchableWithoutFeedback>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 10,
alignItems: "center",
},
inputContainer: {
width: 300,
maxWidth: "80%",
alignItems: "center",
},
input: {
textAlign: "center",
width: 50,
},
});
export default StartGameScreen;
And this is my Card custom component:
function Card(props) {
return (
<View style={{ ...styles.container, ...props.style }}>
{props.children}
</View>
);
}
const styles = StyleSheet.create({
container: {
shadowColor: "black",
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.26,
shadowRadius: 6,
elevation: 12,
backgroundColor: "white",
padding: 20,
borderRadius: 10,
},
});
export default Card;
Change Your Card component like below then it will work
function Card(props) {
return (
<View style={[styles.container,props.style]}>
{props.children}
</View>
);
}
Here, I am fetching data from firebase and then trying to output it in a tinder card like format. My code is as follows -
import React from 'react';
import { View, ImageBackground, Text, Image, TouchableOpacity } from 'react-native';
import CardStack, { Card } from 'react-native-card-stack-swiper';
import City from '../components/City';
import Filters from '../components/Filters';
import CardItem from '../components/CardItem';
import styles from '../assets/styles';
import Demo from '../assets/demo';;
import {db} from '../config/config';
class Home extends React.Component {
constructor (props) {
super(props);
this.state = ({
items: [],
isReady: false,
});
}
componentWillMount() {
let items = [];
db.ref('cards').once('value', (snap) => {
snap.forEach((child) => {
let item = child.val();
item.id = child.key;
items.push({
name: child.val().pet_name,
description: child.val().pet_gender,
pet_age: child.val().pet_age,
pet_breed: child.val().pet_breed,
photoUrl: child.val().photoUrl,
});
});
//console.log(items)
this.setState({ items: items, isReady: true });
console.log(items);
});
}
componentWillUnmount() {
// fix Warning: Can't perform a React state update on an unmounted component
this.setState = (state,callback)=>{
return;
};
}
render() {
return (
<ImageBackground
source={require('../assets/images/bg.png')}
style={styles.bg}
>
<View style={styles.containerHome}>
<View style={styles.top}>
<City />
<Filters />
</View>
<CardStack
loop={true}
verticalSwipe={false}
renderNoMoreCards={() => null}
ref={swiper => {
this.swiper = swiper
}}
>
{this.state.items.map((item, index) => (
<Card key={index}>
<CardItem
//image={item.image}
name={item.name}
description={item.description}
actions
onPressLeft={() => this.swiper.swipeLeft()}
onPressRight={() => this.swiper.swipeRight()}
/>
</Card>
))}
</CardStack>
</View>
</ImageBackground>
);
}
}
export default Home;
I am fetching data and storing it in an array called items[]. Console.log(items) gives me the following result:
Array [
Object {
"description": "male",
"name": "dawn",
"pet_age": "11",
"pet_breed": "golden retriever",
"photoUrl": "picture",
},
Object {
"description": "Male",
"name": "Rambo",
"pet_age": "7",
"pet_breed": "German",
"photoUrl": "https://firebasestorage.googleapis.com/v0/b/woofmatix-50f11.appspot.com/o/pFkdnwKltNVAhC6IQMeSapN0dOp2?alt=media&token=36087dae-f50d-4f1d-9bf6-572fdaac8481",
},
]
Furthermore, I want to output my data in a card like outlook so I made a custom component called CardItem:
import React from 'react';
import styles from '../assets/styles';
import { Text, View, Image, Dimensions, TouchableOpacity } from 'react-native';
import Icon from './Icon';
const CardItem = ({
actions,
description,
image,
matches,
name,
pet_name,
pet_gender,
pet_age,
onPressLeft,
onPressRight,
status,
variant
}) => {
// Custom styling
const fullWidth = Dimensions.get('window').width;
const imageStyle = [
{
borderRadius: 8,
width: variant ? fullWidth / 2 - 30 : fullWidth - 80,
height: variant ? 170 : 350,
margin: variant ? 0 : 20
}
];
const nameStyle = [
{
paddingTop: variant ? 10 : 15,
paddingBottom: variant ? 5 : 7,
color: '#363636',
fontSize: variant ? 15 : 30
}
];
return (
<View style={styles.containerCardItem}>
{/* IMAGE */}
<Image source={image} style={imageStyle} />
{/* MATCHES */}
{matches && (
<View style={styles.matchesCardItem}>
<Text style={styles.matchesTextCardItem}>
<Icon name="heart" /> {matches}% Match!
</Text>
</View>
)}
{/* NAME */}
<Text style={nameStyle}>{name}</Text>
{/* DESCRIPTION */}
{description && (
<Text style={styles.descriptionCardItem}>{description}</Text>
)}
{/* STATUS */}
{status && (
<View style={styles.status}>
<View style={status === 'Online' ? styles.online : styles.offline} />
<Text style={styles.statusText}>{pet_age}</Text>
</View>
)}
{/* ACTIONS */}
{actions && (
<View style={styles.actionsCardItem}>
<View style={styles.buttonContainer}>
<TouchableOpacity style={[styles.button, styles.red]} onPress={() => {
this.swiper.swipeLeft();
}}>
<Image source={require('../assets/red.png')} resizeMode={'contain'} style={{ height: 62, width: 62 }} />
</TouchableOpacity>
<TouchableOpacity style={[styles.button, styles.orange]} onPress={() => {
this.swiper.goBackFromLeft();
}}>
<Image source={require('../assets/back.png')} resizeMode={'contain'} style={{ height: 32, width: 32, borderRadius: 5 }} />
</TouchableOpacity>
<TouchableOpacity style={[styles.button, styles.green]} onPress={() => {
this.swiper.swipeRight();
}}>
<Image source={require('../assets/green.png')} resizeMode={'contain'} style={{ height: 62, width: 62 }} />
</TouchableOpacity>
</View>
</View>
)}
</View>
);
};
export default CardItem;
The problem is when I try to pass the data in my items[] array, the cardItem component just doesnt work. To dry-run, I used a sample demo array and when I use the Demo array, my component works just fine. What am I doing wrong? I have been tinkering with this problem for quite a while now. Any help whatsoever would be appreciated.
I'm making a search bar that displays results live. I've managed to do it properly utilizing SearchBar from 'react-native-elements'. Firstly I had it written as a class component, but decided to rewrite it as a functional component. After rewriting it I'm encountering a bug where the keyboard closes after one letter as seen in the video here
Here is the code of the component
import React, { Component, useEffect, useState } from "react";
import { View, Text, FlatList, TextInput, ListItem } from "react-native";
import { SearchBar } from "react-native-elements";
import { Button } from 'react-native-paper'
import Header from "../navigation/Header";
export default function AktSelect() {
const [data, setData] = useState([])
const [value, setValue] = useState('')
const [akt, setAkt] = useState([])
useEffect(() => {
fetch("http://192.168.5.12:5000/aktprikaz", {
method: "get"
})
.then(res => res.json())
.then(res => setAkt(res));
}, []);
function renderSeparator() {
return (
<View
style={{
height: 1,
width: "100%",
backgroundColor: "#CED0CE"
}}
/>
);
}
function searchItems(text) {
const newData = akt.filter(item => {
const itemData = `${item.title.toUpperCase()}`;
const textData = text.toUpperCase();
return itemData.indexOf(textData) > -1;
});
setData(newData)
setValue(text)
}
function renderHeader() {
return (
<SearchBar
placeholder=" Type Here...Key word"
onChangeText={text => searchItems(text)}
value={value}
lightTheme={true}
/>
);
}
return (
<View
style={{
flex: 1,
width: "98%",
alignSelf: "center",
justifyContent: "center"
}}
>
<Header title='Pretraživanje aktivnosti' />
<FlatList
data={data}
renderItem={({ item }) => (
<View style={{flex: 1}}>
<Text style={{ padding: 10 }}>{item.title} </Text>
<View style={{flexDirection:'row'}}>
<Text style={{ padding: 10 }}>{item.start_time} </Text>
<Button style={{justifyContent: 'flex-end', alignContent: 'flex-end', width:'30%'}} mode='contained' onPress={() => console.log('hi')}>hi</Button>
</View>
</View>
)}
keyExtractor={item => item.id.toString()}
ItemSeparatorComponent={renderSeparator}
ListHeaderComponent={renderHeader}
/>
</View>
);
}
The old class component can be found here
the following code works fine on iOS, but on android after loading the orders array and rendering it, the onpress event stops working, at first I thought it was a problem with firebase but then I did it locally and I get the same issue.
import React from 'react';
import {
ActivityIndicator,
Alert,
Button,
Dimensions,
Image,
StatusBar,
StyleSheet,
ScrollView,
Text,
TouchableOpacity,
View,
Platform,
RefreshControl,
YellowBox } from 'react-native';
import { Ionicons as Icon } from '#expo/vector-icons';
import { Card, DefaultTheme } from 'react-native-paper';
import NavigationService from '../../Navigation/navigationService';
import _ from 'lodash';
YellowBox.ignoreWarnings(['Setting a timer']);
const _console = _.clone(console);
console.warn = message => {
if (message.indexOf('Setting a timer') <= -1) {
_console.warn(message);
}
};
import Firebase from '../../connection/to-firebase';
const LOGO_URL = 'https://i.imgur.com/BbYaucd.png';
const { width: SCREEN_WIDTH, height: SCREEN_HEIGHT } = Dimensions.get('window');
const styles = StyleSheet.create({
container: {
paddingTop: StatusBar.currentHeight,
width: SCREEN_WIDTH,
height: SCREEN_HEIGHT / 2,
backgroundColor: "#317AFA",
},
innerContainer: {width:SCREEN_WIDTH, alignItems: 'center', justifyContent: 'center' },
header: {position:'absolute', padding: 15, paddingTop: Platform.OS === 'ios' ? 13 : 7, marginTop:SCREEN_HEIGHT*0.05,zIndex:99 },
scrollView: {
position:'absolute',
top:SCREEN_HEIGHT*0.35,
marginHorizontal: 20,
width: SCREEN_WIDTH*0.90,
height: SCREEN_HEIGHT,
zIndex:9999
},
textHeader:{
marginTop:10,
color: 'white',
fontWeight: 'bold',
fontSize: 40,
}
});
const theme = {
colors: {
...DefaultTheme.colors,
primary: '#3498db',
accent: '#f1c40f',
}
}
export default class DefaultScreen extends React.Component {
constructor (props) {
super(props)
console.ignoredYellowBox = [
'Setting a timer'
];
this.state = {
orders: [],
refreshing: false,
timePassed: false
}
}
_onRefresh = () => {
this.setState({refreshing: true});
this.getOrders().then(() => {
this.setState({refreshing: false});
});
//setTimeout(()=>{this.setState({refreshing: false})},1000)
}
async getOrders(){
//let result = await Firebase.extractOrder();
let result = [
{
"Note": "",
"coords": {
"finalLatitude": 14.100751767597542,
"finalLongitude": -87.18541710839844,
"initialLatitude": 14.061113522979957,
"initialLongitude": -87.21807641015624
},
"createdAt": {
"nanoseconds": 686000000,
"seconds": 1576188983
},
"destinataryName": "Eliana Martínez",
"destinataryPhone": "97412032",
"idSubcategory": "1",
"idUsuario": 1,
"isTakenBySomeone": false,
"orderID": "rQAt5IEI687AkoI8rShh",
"products": [
{
"id": 93634,
"observation": "",
"price": "56.00",
"quantity": 1
},
{
"id": 29909,
"observation": "",
"price": "131.00",
"quantity": 97
}
],
"status": "Pending",
"telephone": 23456987,
"transportType": "Motocicleta"
}
]
this.setState({ orders: result});
}
componentDidMount(){
//this.getOrders();
}
renderOrders = (orders) =>{
return orders.map((a,b)=>{
return [
<MainOrders key={a.orderID} dName= {a.orderID} note ={a.Note} transType={a.transportType} orderDetails={a}
navigation={this.props.navigation}
/>
]
})
}
render() {
setTimeout(()=>{this.setState({timePassed: true})}, 1000);
if (!this.state.timePassed){
return (
<View style={styles.container}>
<StatusBar barStyle="dark-content" />
<View style={styles.header}>
<TouchableOpacity
onPress={() => {
this.props.navigation.openDrawer();
}}
style = {{marginTop:'10%'}}
>
<Icon name="md-menu" size={35} color={'#fff'}/>
</TouchableOpacity>
<Text style={styles.textHeader}>Home</Text>
</View>
<View style={styles.innerContainer}>
<ScrollView style={styles.scrollView}
refreshControl={ <RefreshControl refreshing={this.state.refreshing} onRefresh={this._onRefresh}/>}
>
<Card theme={theme}>
<Card.Title title="Order List" subtitle="" />
<Card.Content>
<ActivityIndicator size="small" color="#317AFA" />
</Card.Content>
<Card.Actions>
<Button title="View Order" style={{zIndex:9999, elevation:15}} onPress={()=>{
Alert.alert('Hello World')
}}>View Order</Button>
</Card.Actions>
</Card>
</ScrollView>
</View>
</View>
);
}
else{
const {orders,navigation} = this.state;
DefaultScreen.navigationOptions = {
title: ''
}
return (
<View style={styles.container}>
<StatusBar barStyle="dark-content" />
<View style={styles.header}>
<TouchableOpacity
onPress={() => {
this.props.navigation.openDrawer();
}}
style = {{marginTop:'10%'}}
>
<Icon name="md-menu" size={35} color={'#fff'}/>
</TouchableOpacity>
<Text style={styles.textHeader}>Home</Text>
</View>
<View style={styles.innerContainer}>
<ScrollView style={styles.scrollView}
refreshControl={ <RefreshControl refreshing={this.state.refreshing} onRefresh={this._onRefresh}/>}
>
<Card theme={theme}
>
<Card.Title title="Order List" subtitle="" />
<Card.Content>
{
orders.map((a,b)=>{
return [
<MainOrders key={a.orderID} dName= {a.orderID} note ={a.Note} transType={a.transportType} orderDetails={a}
navigation={this.props.navigation}
/>
]
})
}
</Card.Content>
<Card.Actions>
<Button title="Press me" style={{zIndex:9999}} onPress={()=>{
Alert.alert('Hello World')
}}> Press me</Button>
</Card.Actions>
</Card>
</ScrollView>
</View>
</View>
);
}
}
}
class MainOrders extends React.Component {
constructor() {
super();
}
render() {
return (
<View style={{marginTop:2,marginBottom:2}}>
<Card theme={theme}>
<Card.Title title={this.props.dName} subtitle={this.props.note} />
<Card.Content>
<Text>{this.props.transType}</Text>
</Card.Content>
<Card.Actions>
<Button title="view order" style={{zIndex:9999}} onPress={()=>{
this.props.navigation.navigate('orderDetails',{orderDetails: this.props.orderDetails})
}}> view order</Button>
</Card.Actions>
</Card>
</View>
);
}
}
I tried changing the execution orders,
setting timeout and when I manually filled out the order array was that I realized that the problem is at that point, but I can't see what I'm doing wrong.
"react-native": "0.59.8"
Thanks.
Code :
import React, { useState } from 'react';
import { StyleSheet, Text, View, Button, TextInput, ScrollView, FlatList } from 'react-native';
import GoalItem from './components/GoalItem';
export default function App() {
const [enteredGoal, setEnteredGoal] = useState('');
const [courseGoals, setCourseGoals] = useState([]);
const goalInputHandler = (enteredText) => {
setEnteredGoal(enteredText);
};
const addGoalHandler = () => {
//console.log(enteredGoal);
setCourseGoals(currentGoals => [...currentGoals, { id: Math.random().toString(), value: enteredGoal }]);
};
return (
<View style={styles.screen}>
<View style={styles.inputContainer}>
<TextInput placeholder="Course Goal" style={styles.input}
onChangeText={goalInputHandler} value={enteredGoal} />
<Button title="Add" onPress={addGoalHandler} />
</View>
<FlatList keyExtractor={(item, index) => item.id} data={courseGoals}
renderItem={itemData => <GoalItem title={itemData.item.value} />}
/>
</View>
);
}
const styles = StyleSheet.create({
screen: {
padding: 50
},
inputContainer: {
flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'
},
input: {
width: '70%', borderBottomColor: 'black', borderWidth: 1, padding: 10
},
});
GoalItem Components :
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
const GoalItem = props => {
return (
<View style={styles.listItem}>
<Text>{props.title}</Text>
</View>
);
};
const styles = StyleSheet.create({
listItem: {
padding: 10, backgroundColor: '#ccc', borderColor: 'black', borderWidth: 1, marginVertical: 10
}
});
export default GoalItem;
Error : Below is the code, please check Can't find variable itemData
in react-native
Pls i am a newbie in react-native i just got for about two hours. Any
help would be appreciated. Thanks in advance. Look into the code and share some advice so that the code works well..
Thanks :)
It should be
<FlatList keyExtractor={(item, index) => item.id}
data={courseGoals}
renderItem={(itemData) => <GoalItem title={itemData.item.value} }/>
Or
<FlatList keyExtractor={(item, index) => item.id}
data={courseGoals}
renderItem={({item}) => <GoalItem title={item.value} }/>
it should be like this :
<FlatList
data={courseGoals}
renderItem={itemData => (
<View style={styles.listItem}>
<Text>{itemData.item}</Text>
</View>
)}
/>