Adding dynamic local images in a react native listview - javascript

I'm trying to load some local images in a simple app that I'm making using react native.
I'm following the guide here - https://facebook.github.io/react-native/docs/images.html
Unfortunately, that guide says the following:
Note that in order for this to work, the image name in require has to be known statically.
Which is why my code isn't working when I try to render rows in a list view:
renderRow(chat){
return (
<View style={ styles.row }>
<Image
source={require(`../images/${chat.image}`)} //this is the part that's not working. It can't require a dynamic path
style={ styles.cellImage }
/>
</View>
);
}
How can I achieve this? Or can you suggest another way that will work?

It's quirky and odd, but if you have a set number of options for the images (which makes sense if the images are living in the project) then you can return the statically required image based on a given condition.
getSource() {
if (condition) {
return require( '../images/option-one' );
} else {
return require( '../images/default-option' );
}
}
renderRow(chat){
return (
<View style={ styles.row }>
<Image
source={ this.getSource() }
style={ styles.cellImage }
/>
</View>
);
}

Related

React Native Prevent Undefined Objects

I am grabbing data from an API to display an image based on the API value. The following code works perfect IF there is an image in the object. If an API item does not have an image the app throws an "Undefined is not an object" error.
<View>
<Image source={{uri:props.enclosures[0].url}} style={styles.mainPhoto} />
</View>
I have tried the following code to check if the value exists first, but it still throws exact same error if an API item does not have image.
<View>
{props.enclosures[0].url ?
<Image source={{uri:props.enclosures[0].url}} style={styles.mainPhoto} />
:
<Text>No Image</Text>
}
</View>
If you are going to access multiple properties of a nested object, you should check everything, like so
<View> // Checking everthing so it never throws an error
{props.enclosures && props.enclosures[0] && props.enclosures[0].url ?
<Image source={{uri:props.enclosures[0].url}} style={styles.mainPhoto} />
:
<Text>No Image</Text>
}
</View>
To prevent undefined error you can also use path from Ramda library. It allows you to safely access any nested object/array.
const MyComponent = (props) => {
const apiImage = path(["enclosures", 0, "url"], props);
return {
<View>
{apiImage ?
<Image source={{uri:apiImage}} style={styles.mainPhoto} />
:
<Text>No Image</Text>
}
</View>
}
}

How to show images dynamically with react native

I want to build an album app with react native, the main idea is to use a sectionList and show the data in an array like this:
class CustomImage extends Component{
render(){
return(
<View>
<Image style={styles.Img} source={this.props.imageName} />
<Text style={styles.text}>{this.props.name}</Text>
</View>
);
}
}
export default class DisplayAnImage extends Component {
render() {
return (
<View>
<SectionList
sections={[
{titile: 'small soldier', data: ["./gifs/2.gif", "./gifs/3.gif", "./gifs/4.gif"]}
]}
renderItem={({item}) => <CustomImage name={item} fromWeb={false} imageName={require(item)} />}
renderSectionHeader={({section}) => <Text style={styles.sectionHeader}>{section.title}</Text>}
/>
</View>
);
}
}
Above code was indented to make it work inspirited by this answer
I have already put the gifs folder under the project folder, and if I using a static string as source={require(url)} in the Image component, things will work, but when the url came out of an array items iteration, it will not work.
How can I make this work with react native?
EDIT
Don't know if I could edit to make it more specificly, the really thing I want to do is to use a generated array like this:
function numberRange(start, end){
return new Array(end-start).fill().map((d,i) => {
var url = "./gifs/" + ( i+start) + ".gif";
return require(url)
});
}
export default class DisplayAnImage extends Component {
render() {
return (
<View>
<SectionList
sections={[
{title: 'small soldier', data: numberRange(2,30)},
{title: 'small soldier', data: numberRange(31,60)}
]}
renderItem={({item}) => <CustomImage name={item} fromWeb={false} imageName={item} />}
renderSectionHeader={({section}) => <Text style={styles.sectionHeader}>{section.title}</Text>}
/>
</View>
);
}
}
Don't know if have a way to use this array generator to make an array or I have to enter the path one by one on bare hand :-(
require is a javascript keyword with a preload nature.
And, images will not related to path at runtime --- provide a path to it will not get anything. it becomes bundle resources, so with console.log you can only see resource token related to bundle ex: _1 _2.
It will not work even change require("./gifs/1.gif") to require("./gifs/"+"1.gif").
Try this:
data: [require("./gifs/2.gif"), require("./gifs/3.gif"), require("./gifs/4.gif")]

Returning multiple components results in a libART error

I am using the react-native-chart module to display charts in my app, and I wanted to add a touchable functionality to the the plotted dots on the chart, so I went into the library and tried to wrap this with a <TouchableOpacity> component: https://github.com/tomauty/react-native-chart/blob/master/src/LineChart.js#L168
When I tried running my app, I get these errors from xcode:
Reproduction
By Installing the react-native-chart module directly from github, then trying to wrap this with TouchableOpacity https://github.com/tomauty/react-native-chart/blob/master/src/LineChart.js#L168
return (
<View>
<View style={{ position: 'absolute' }}>
<Surface width={containerWidth} height={containerHeight}>
{ multipleLines }
{ multipleFills }
</Surface>
</View>
<View style={{ position: 'absolute' }}>
<Surface width={containerWidth} height={containerHeight} />
</View>
{(() => {
if (!this.props.showDataPoint) return null;
var multipleDataPoints = dataPoints.map( (dataPointSet, index) => {
let totalDataSet = dataPointSet.map((d, i) => {
return (
// <TouchableOpacity>
<Circle key={i} {...d} onPress={()=>alert(i)} />
// </TouchableOpacity>
);
});
return totalDataSet;
});
return (
<Surface width={containerWidth} height={containerHeight}>
{ multipleDataPoints }
</Surface>
);
})()}
</View>
);
Additional Information
React Native version: 0.39.2
Platform: iOS
Operating System: MacOSX 10.12.2
You cannot add Circle component inside TouchableOpacity. ReactArt expects Surface component children to be instance ARTNode in native side. You can try sending pandresponder properties to Circle component. From reading core code, it seems that should work. I haven't tried it on ReactArt by myself yet.

React Native error: undefined is not an object (evaluating '_this2.props.navigator.push')

So Basically I am getting error in the title which is related to the navigator.
The error pops up when I press on the Icon.
What I basically want to do is make a Tab bar at the top that switches between three different views: feed, wiki, and message board
Here is my index.android.js: (imports Nav)
_renderScene(route, navigator) {
var globalNavigatorProps = {navigator};
switch(route.ident) {
case "FeedView":
return(
<Feed
{...globalNavigatorProps}
/>
);
case "WikiView":
return(
<View>
<Text>
{'Hello'};
</Text>
</View>
);
case "BoardView":
return(
<View>
<Text>
{'Hello'};
</Text>
</View>
);
default:
console.log(`Something went wrong ${route}`);
}
}
render(){
return(
<View>
<Nav />
<Navigator
initialRoute={{ident:"Feed"}}
ref="appNavigator"
renderScene={ this._renderScene }
/>
</View>
);
}
Here is my Nav.js:
constructor(props){
super(props);
}
render(){
console.log(this.props.navigator);
return(
<View style={{flexDirection: "column"}}>
<View style={styles.nav}>
<Icon onPress={(event) => this.props.navigator.push({ident: "Feed"})} name="newspaper-o" size={22}/>
<Icon name="wikipedia-w" size={22}/>
<Icon name="comments" size={22}/>
</View>
<View style={styles.divider}/>
</View>
);
}
_changeView(type){
}
I dont think this is the issue, but the renderScene function won't be bound to the react component.
Try turning renderScene={ this._renderScene } into renderScene={ this._renderScene.bind(this) }
If you are trying to implement a tabbed view there are better ways of doing it you can always use an open source module such as this one https://github.com/skv-headless/react-native-scrollable-tab-view
the developer has made it in such a way that it is easy to use and the example is good enough to get through most of the part.
So instead of creating such components yourself what I would suggest is to use the modules made by the community.
Hope my answer was helpful.
this error always occurs when you didnt bind(this),check you Icon module onPress method

Creating custom components

I've been trying to get a UITableView equivalent in React-Native. The screen looks like this (work in progress):
The code for this is quite primitive at the moment:
class SettingsView extends Component {
render() {
return(
<View style={styles.container}>
//more View code
//example of a cell
<TouchableHighlight style={styles.tableViewCell}>
<Text style={styles.cellLabel}>Log Out</Text>
</TouchableHighlight>
</View>
);
}
}
It works fine, I've been trying to create an accessory - an > indicator - for all my cells. Whilst doing that, I stumbled upon a way to create custom component via this code:
class TableViewCell extends Component {
render() {
return (
<TouchableHighlight style={styles.tableViewCell}>
<Text style={styles.cellLabel}>Log Out</Text>
</TouchableHighlight>
);
}
}
Next, I replaced the initial block of code and I came out with this:
class SettingsView extends Component {
render() {
return(
<View style={styles.container}>
//more View code
//example of a cell
//Replaces the previous block of TouchableHighlight
<TableViewCell/>
</View>
);
}
}
Wow. To a native Swift developer that has barely any experience with HTML and JavaScript, this is amazing. I immediately went on quest in an attempt to find out how I might make this reusable. Currently, TableViewCell is hardcoded to have the text "Log Out". Ideally I want to be able to supply the text as an argument for the constructor. This is where I got stuck. Here's what I've tried so far:
Use getAttribute to see if I could extract an attribute that I would pass in whilst declaring the TableViewCell tag.
//when declaring a cell on the screen's render
<TableViewCell titleText="About"/>
//tableViewCell component
render() {
return(
<TouchableHighlight ...>
<Text>{this.getAttribute("titleText")}</Text>
</TouchableHighlight>
);
}
I couldn't get a reference to the titleText that I've declared as part of the tag. Any ideas?
I could be wrong, but I'm pretty sure this is what you need. You can pass properties to components and receive them as this.props:
// when declaring a cell on the screen's render
<TableViewCell titleText="About"/>
// tableViewCell component
render() {
return(
<TouchableHighlight ...>
<Text>{this.props.titleText}</Text>
</TouchableHighlight>
);
}

Categories