4

I have defined a React Native class that is designed to fill a "tableView" cell with an image reference that is a prop input to the class. This is invoked with the use of FlatList. However, this class is unable to find the input image reference in the bundle when specified using an Image source tag. It can only be found if it is a hard coded reference.

The class is defined as follows:

class ListItem extends React.PureComponent {
    _onPress = () => {
        this.props.onPressItem(this.props.index);
    }

    render() {
        const item = this.props.item; 

        console.log("ChannelSelection Mix Button artwork: ", item.artwork);
        return (
          <TouchableHighlight
            onPress={this._onPress}
            underlayColor="transparent">
            <View>
              <View style={styles.rowContainer}>
                <Image source={{ uri: item.artwork }} style={styles.buttonContainer} />
                <View style={styles.mixButtonTitleContainer}>
                  <Text style={styles.mixButtonTitle}
                    numberOfLines={2}>{item.channelTitle}</Text>
                </View>
              </View>
            </View>
          </TouchableHighlight>
        );
    }
}

When this class in invoked, I get a warning that says:

Warning
Could not find image file:///Users/myname/Library/Developer/CoreSimulator/Devices/34AE8A68-E69D-4804-B3C4-96DE7A051B9B/data/Containers/Bundle/Application/C79368E9-3D1B-492C-B72B-9BF5C4D3262B/myApp.app/./Resources/MissingAlbumArt.png

The console output to print item.artwork is:

'ChannelSelection Mix Button artwork: ', './Resources/MissingAlbumArt.png'

so you can see that the name of the file is being passed in correctly.

Note that if I change the line:

<Image source={{ uri: item.artwork }} style={styles.buttonContainer} />

to:

<Image source={require('./Resources/MissingAlbumArt.png')} style={styles.buttonContainer} />

then the error goes away.

So, how can I properly reference the .png files in my Resources directory? And why are my .png files not in the Resources directory of my bundle?

1 Answer 1

9

Using images with require

One way of using images is in the bundle. You access these images by using

const imageName = require('./path/to/the/image/imageName.png'); 

For images that I add this way I actually create a file (called Images.js) that contains all of my requires and then exports the images. So in the file it would be a list of requires like this

export const imageName = require('./path/to/the/image/imageName.png'); 

Then when I want to use the image I import the image like so:

import { imageName } from '.path/to/Images.js';

Using images on the device

Another way is to download the file and then save it in the documents directory of the application. Usually you use rn-fetch-blob or react-native-fs to download and save the file to a location, like the documents directory.

You would then construct the the path to the file and use that. So for example, if you were using react-native-fs you could construct the path in the following way,

let pathToImage = RNFS.DocumentDirectoryPath + '/path/to/dowloaded/file/imageName.png'

What's happening in your situation

You are mixing the two methods up. The images haven't been stored on your device when you are working in development. They are currently served to the device by the bundler. That way you have to use the require method to access them. They get copied across when you use them (look at the logs in your bundler and you will see it happening).

When you create your production ipa or apk all the images and code get bundled together and added to the app, the require statements tell the device where to find the images in that bundle. If you were to try to use the path of the file after it has been bundled into an ipa or apk it wouldn't work in development and you would end up with a similar error.

If you try to access the file using a path similar to the one below, it won't work as that file isn't there because the file is in the bundle. It is best to use the require method.

file:///Users/myname/Library/Developer/CoreSimulator/Devices/34AE8A68-E69D-4804-B3C4-96DE7A051B9B/data/Containers/Bundle/Application/C79368E9-3D1B-492C-B72B-9BF5C4D3262B/myApp.app/./Resources/MissingAlbumArt.png 

One thing to also note is that iOS cannot guarantee that paths to files will remain static. If you run react-native run-ios although the application is reloaded and only one application appears on device, it can actually move folders so it is always best to dynamically construct links to files that you have saved to any directory on iOS.

Snack

Here is a snack that shows using Images.js to store all the require for the files. https://snack.expo.io/@andypandy/requiring-images

Here is the directory structure that I have in this project

├── App.js
├── Images.js
├── README.md
├── app.json
├── assets
│   ├── bart.png
│   ├── lisa.png
│   ├── maggie.png
│   └── parents
│       ├── homer.jpg
│       └── marge.jpg
├── components
│   ├── AssetExample.js
│   └── SecondAssetExample.js
└── package.json

Here is how I am constructing the require statements in the Images.js

export const MARGE = require('./assets/parents/marge.jpg');
export const HOMER = require('./assets/parents/homer.jpg');
export const BART = require('./assets/bart.png');
export const MAGGIE = require('./assets/maggie.png');
export const LISA = require('./assets/lisa.png');
Sign up to request clarification or add additional context in comments.

10 Comments

I tried your idea of creating a Images.js file with exports for each .png file, but am getting an error. The lines of the file look like this: export const MissingAlbumArt = require('./Resources/MissingAlbumArt.png'); The error I am getting is "Requiring unknown module '694'. If you are sure the file is there, try restarting metro bundler. ..." Did I implement this as you suggested?
Your file paths really depend on where you store the files, you should make sure that they are correct. Usually when adding new files to a project I like to make sure that my metro bundler is clear. That error is usually because you have added/removed something and it is looking for it. Clear your cache, clean your build folders and try re-building the project
You can have a separate directory you just have to put the correct path in the require. I don't know how you have setup your project and where you have put your files. The path in the require is relative to where the Image.js file is. Your import statement should be import { MissingAlbumArt } from './Images.js' note the {} around the MissingAlbumArt
No, that seems correct. It gives a reference that it can use to find the image. I have added a snack so you can see a sample folder structure with it working. The folder structure is incidental as it can be anything, you just have to use the correct paths to the images you require and the correct path when you are importing Images.js
I showed an example in the snack of passing an object containing the reference to an image. Look at what I am passing to the SecondAssetExample. As a bonus here is a snack that incorporates a FlatList.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.