Displaying Images and text in ListView for React Native - react-native

I am trying to load images via a url and text using ListView and show data into List but when I populate it in a listview Image and text then my images are not show.
My code is:
import React, { Component } from "react";
import { ListView, Text, View, Image, StyleSheet } from "react-native";
const styles = Style.create({
container: {
flex: 1,
marginTop: 20
}
});
class ListViewDemo extends React.Component {
constructor(props) {
super(props);
const ds = new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2
});
this.state = {
dataSource: ds.cloneWithRows(["row 1", "row 2"])
};
}
render() {
return (
<ListView
dataSource={this.state.dataSource}
renderRow={data => {
<View style={styles.container}>
<Image
source={{
uri:
"https://upload.wikimedia.org/wikipedia/commons/d/de/Bananavarieties.jpg"
}}
style={{ width: 193, height: 110 }}
/>
<Text> Asad </Text>
</View>;
}}
/>
);
}
} [enter image description here][1]
export default ListViewDemo;

Problem
The images would not render in your list view.
Solution
I have noticed sometimes having trouble getting images to show up when components render in react. Especially when they are loaded over a network call. I added a style to your image component, placed the image source into a variable and fixed some syntax errors you had in your code.
The biggest problem, and the reason it was not rendering the image was you added {} around your renderRow prop which would call for the need of a return statement. When you supply () around the return data, return is implied because your using a fat arrow function.
So this,
renderRow = { (data) => { }}
Became this,
renderRow={data => ( )}
Example
You can copy and paste this whole component into you code and it will work.
This has been tested,
import React, { Component } from 'react'; import { ListView, Text, View, Image, StyleSheet } from 'react-native';
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: 20,
},
img: {
width: 193,
height: 110,
},
});
class ListViewDemo extends Component {
constructor(props) {
super(props);
const ds = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 });
this.state = {
dataSource: ds.cloneWithRows(['row 1', 'row 2']),
};
}
render() {
const imageSource = 'https://upload.wikimedia.org/wikipedia/commons/d/de/Bananavarieties.jpg';
return (
<ListView
dataSource={this.state.dataSource}
renderRow={data => (
<View style={styles.container}>
<Image
source={{ uri: imageSource }}
style={styles.img}
/>
<Text>{data}</Text>
</View>)}
/>
);
}
}
export default ListViewDemo;
Proof of Concept
Please see the image showing your component working now,

React Native provides a suite of components for presenting lists of data. Generally, you'll want to use either FlatList or SectionList first and then provide the image in the data source.
import React from 'react';
import { FlatList, StyleSheet, Text, View } from 'react-native';
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 22
},
item: {
padding: 10,
fontSize: 18,
height: 44,
},
img: {
width: 100,
height: 100
},
});
const FlatListBasics = () => {
return (
<View style={styles.container}>
<FlatList
data={[
{key: 'Devin', image: 'image1.png'},
{key: 'Dan', image:'image2.png'},
]}
renderItem={({item}) => <Image source={item.image} style={styles.img} /><Text style={styles.item}>{item.key}</Text>}
/>
</View>
);
}
export default FlatListBasics;
reference: https://reactnative.dev/docs/using-a-listview

Related

Unable to Apply Layout Animation Using Reanimated API

I'm trying to apply layout animation to a FlatList upon adding and deleting a goal (list item) using the Reanimated API. I'm mainly following this tutorial from the Reanimated docs but I don't know why the animation is not applied when list items are added or removed. I should also inform that I'm only testing this on an Android device. Here is the code:
App.js (contains FlatList)
import { useState } from "react";
import { Button, FlatList, StyleSheet, View } from "react-native";
import GoalInput from "./components/GoalInput";
import GoalItem from "./components/GoalItem";
export default function App() {
const [goalList, setGoalList] = useState([]);
const [isModalOpen, setIsModalOpen] = useState(false);
const styles = StyleSheet.create({
appContainer: {
paddingTop: 50,
},
});
function startAddGoalHandler() {
setIsModalOpen(true);
}
// spread existing goals and add new goal
function addGoalHandler(enteredGoalText) {
setGoalList((currentGoals) => [
...currentGoals,
{ text: enteredGoalText, id: Math.random().toString() },
]);
}
function deleteGoalHandler(id) {
setGoalList((currentGoals) =>
currentGoals.filter((existingGoals) => existingGoals.id !== id)
);
}
return (
<View style={styles.appContainer}>
<Button
title='Add New Goal'
color='indigo'
onPress={startAddGoalHandler}
/>
{isModalOpen && (
<GoalInput
isModalOpen={isModalOpen}
setIsModalOpen={setIsModalOpen}
onAddGoal={addGoalHandler}
></GoalInput>
)}
<FlatList
keyExtractor={(item, index) => {
return item.id;
}}
data={goalList}
renderItem={(itemData) => {
return (
<GoalItem
onGoalDelete={deleteGoalHandler}
itemData={itemData}
/>
);
}}
/>
</View>
);
}
GoalItem.js (list item)
import React from "react";
import { Pressable, StyleSheet, Text } from "react-native";
import Animated, { Layout, LightSpeedInLeft, LightSpeedOutRight } from "react-native-reanimated";
const GoalItem = ({ itemData, onGoalDelete }) => {
const styles = StyleSheet.create({
goalCards: {
elevation: 20,
backgroundColor: "white",
shadowColor: "black",
height: 60,
marginHorizontal: 20,
marginVertical: 10,
borderRadius: 10,
},
});
return (
<Animated.View
style={styles.goalCards}
entering={LightSpeedInLeft}
exiting={LightSpeedOutRight}
layout={Layout.springify()}
>
<Pressable
style={{ padding: 20 }}
android_ripple={{ color: "#dddddd" }}
onPress={() => onGoalDelete(itemData.item.id)}
>
<Text style={{ textAlign: "center" }}>
{itemData.item.text}
</Text>
</Pressable>
</Animated.View>
);
};
export default GoalItem;
I've even tried replacing the FlatList with View but to no avail. I suspect that Reanimated isn't properly configured for my project, if I wrap some components with <Animated.View>...</Animated.View> (Animated from Reanimated and not the core react-native module) for example the child components will not show. Reanimated is installed through npm
Any help is appreciated, thanks!

Flatlist rendering empty space

i'm new to react native and trying to use flatlist inside another component that's been rendered by another flatlist.
My concern is in the nested flatlist used like this:
Card component
import React, { useContext } from "react"
import { View, Image, Text, StyleSheet, FlatList } from "react-native";
import { QueryContext } from "../context/QueryContext"
function Card(props) {
const [query, setQuery] = useContext(QueryContext)
const { genres_list } = query
const { posterURLs, originalTitle, genres } = props
const listData = []
genres.forEach(genre => {
listData.push({ key: genres_list[genre] })
})
const renderItem = (item) => {
return (
<View>
<Text style={styles.item}>
{item.index}
{item.key}
</Text>
</View>
)
}
return (
<View style={styles.container}>
<Image
style={styles.images}
source={{ uri: posterURLs["original"] }} />
<Text style={styles.title}>{originalTitle}</Text>
<FlatList
data={listData}
renderItem={renderItem}
keyExtractor={(item)=> item.key}
/>
</View>
);
}
const styles = StyleSheet.create({
images: {
width: 400,
height: 500
},
container: {
flex: 1,
backgroundColor: 'lightgrey',
justifyContent: 'center',
alignItems: 'center',
},
title: {
fontSize: 30
},
item: {
padding: 10,
fontSize: 15,
color: "red",
},
})
I have to prepare the data for the flatlist since is inside an object that comes from the context. Weirdly enough i can see the index from item.index but not the item.key which makes me think is some styling issue but as much change i make i'm unable to see it
The card component is rendered by another flatlist and i don't know if that matters or not.
Thanks in advance
Nothing was showing because the data item.key values were actually stored in item.item.key

ReactNative Android :How to set text to image when using image in nested text

I used nested Text to add an image between the texts.
After that I tried to get the original string value but the string in the image is replaced with I.
import * as React from 'react';
import { Text, View, StyleSheet,TextInput,Button,Image } from 'react-native';
import Constants from 'expo-constants';
// or any pure javascript modules available in npm
export default class App extends React.Component {
state = {
text: '',
images:[],
}
changeText = (text) => {
this.setState({
text,
});
}
parseText = () => {
const { text,images } = this.state;
if (images.length !== 0){
return(
<Text>
{text}
{images}
</Text>
);
}
return text;
}
addImage = () => {
const { images } = this.state;
const newImage = (<Image
style={{width:20,height:20}}
source={require('./assets/snack-icon.png')} />);
this.setState({
images:[...images , newImage],
})
}
render() {
return (
<View style={styles.container}>
<TextInput
style={{flex:1}}
onChangeText={this.changeText}
placeholder="test"
>
{this.parseText()}
</TextInput>
<Button
title="add Image"
onPress={this.addImage}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
});
https://snack.expo.io/rkjP70hUS
This example is intended to illustrate the approximate situation but not the same as mine.
In this example, when you add an image and import text, the image comes out as I.
Can I change to the string instead of I?

How Can I Display SVG Data In React Native?

I have some SVG image data that I would like to import into my React Native App.
Is there any way to take my raw SVG image data and display it without saving it to a file?
I have an api that will create an image based from any given text (coolProgrammer123) and will return the SVG image data.
https://api.kwelo.com/v1/media/identicon/coolProgrammer123?format=base64
Any Ideas? Thanks.
I'll suggest you try out react-native-svg-uri
import SvgUri from 'react-native-svg-uri';
const TestSvgUri = () => (
<View style={styles.container}>
<SvgUri
width="200"
height="200"
source={{uri:'http://thenewcode.com/assets/images/thumbnails/homer-simpson.svg'}}
/>
</View>
);
UPDATE
Here is a code snippet on how you can use to use axios to get the SVG from the URL and pass it to the Image tag without using the above npm package.
import React, { Component } from 'react';
import { View, Image } from 'react-native';
import axios from 'axios';
class App extends Component {
constructor(props) {
super(props);
this.state = {
imageUri: ''
}
}
componentDidMount() {
this.getSvg();
}
getSvg = () => {
let image_base64;
axios.get('https://api.kwelo.com/v1/media/identicon/coolProgrammer123?format=base64')
.then(response => {
image_base64 = response.data;
this.setState({
...this.state,
imageUri: image_base64
})
})
.catch(function (error) {
console.log(error);
});
return image_base64;
}
render(){
return (
<View>
<Image
style={{
width: 81,
height: 81,
resizeMode: 'contain',
marginTop: 180,
marginLeft: 20,
marginRight: 20,
alignSelf: "center"
}}
source={{ uri: this.state.imageUri }}
/>
</View>
);
}
};
export default App;

State does not change until the second button press? Adding a call back throws an error "invariant violation: invalid argument passed"

I'm trying to render a Flatlist that contains a store name. Upon clicking the store name, more information about the store should be displayed.
I attempted to change state and then use
{this.renderMoreDetails(item) && this.state.moreDetailsShown}
to get the additional information to appear. However, it was clear via console.log that state was only changed after a second button press.
From what I read in this article 1 and this article 2 it seemed as though I needed a callback function as an additional parameter to my setState().
I tried adding a callback function(probably incorrect, but I'm extremely lost at this point) and only got more errors.
I know that I have access to all of the data from renderItem inside FlatList. How do I make it appear upon click?
import React, { Component } from 'react';
import {
View,
FlatList,
Text,
TouchableWithoutFeedback,
ListView,
ScrollView
} from 'react-native'
import { NavigationActions } from 'react-navigation';
import { Header, Card, CardSection } from '../common';
import Config from '../Config';
export default class Costco extends Component<Props> {
constructor(props) {
super(props);
this.state = {
stores: [],
selectedItem: {id: null},
};
}
componentWillMount() {
const obj = Config.costcoThree;
const costcoArr = Object.values(obj);
this.setState({
stores: costcoArr,
})
}
renderListOfStores() {
return <FlatList
data={this.state.stores}
renderItem={ ({item}) => this.singleStore(item)}
keyExtractor={(item) => item.id}
extraData={this.state.selectedItem} />
}
singleStore(item) {
console.log(this.state.selectedItem.id)
return item.id === this.state.selectedItem.id ?
<TouchableWithoutFeedback
onPress={() => this.selectStore(item)}
>
<View>
<Text>{item.branchName}</Text>
<Text>Opening Time {item.openingTime}</Text>
<Text>Closing Time {item.closingTime}</Text>
<Text>Address {item.dongAddKor}</Text>
</View>
</TouchableWithoutFeedback>
:
<TouchableWithoutFeedback>
<View>
<Text>{item.branchName}</Text>
<Text>Only showing second part</Text>
</View>
</TouchableWithoutFeedback>
}
selectStore(item) {
this.setState({selectedItem: item});
console.log('repssed');
}
render() {
return(
<ScrollView>
<Header headerText="Costco"/>
<Text>hello</Text>
{this.renderListOfStores()}
</ScrollView>
)
}
}
as a workaround you can have a state that maintain your selected item to expand(or something like another view) and then you can use some conditions to work for render your flat list data.
Consider the below code and let me know if you need some more clarification.
import React, { Component } from 'react';
import {
Platform,
StyleSheet,
Text,FlatList,TouchableNativeFeedback,
View
} from 'react-native';
export default class App extends Component<Props> {
constructor(props) {
super(props);
this.state = {
response: [],
selectedItem: {id: null},
};
}
userListLayout() {
const {response} = this.state;
return <FlatList data={response} renderItem={ ({item}) => this.singleUserLayout(item)} keyExtractor={(item) => item.email} extraData={this.state.selectedItem} />
}
singleUserLayout(item) {
return item.id == this.state.selectedItem.id ?
<TouchableNativeFeedback onPress={() => this.userSelected(item)}>
<View style={{flex:1, borderColor: 'black', borderWidth: 1}}>
<Text style={{padding: 10, fontSize: 25}}>{item.email}</Text>
<Text style={{padding: 10,fontSize: 20}}>{item.name}</Text>
</View>
</TouchableNativeFeedback>
: <TouchableNativeFeedback onPress={() => this.userSelected(item)}><Text style={{padding: 10,fontSize: 20}}>{item.email}</Text></TouchableNativeFeedback>
}
userSelected(item) {
console.log(item)
this.setState({selectedItem: item})
}
componentDidMount() {
fetch("https://jsonplaceholder.typicode.com/users")
.then(data => data.json())
.then(response => this.setState({response}))
}
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>HI THERE</Text>
{this.userListLayout()}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});