Working with the React Native Image Component for Custom Navigation Header Styles
This is gonna be a really cool guide because, in this guide, you're gonna learn how to build a feature that you're most likely gonna have to build into any React Native application that you ever work on.
Guide Tasks
  • Read Tutorial
  • Watch Guide Video
Video locked
This video is viewable to users with a Bottega Bootcamp license

You're going to learn how to implement a custom image into that navigation bar. So right up here, you can see we have by default the name of the screen that's being used and there are certain situations where you might wanna have that. But typically, if you look at professional applications, they usually have some type of image or logo up there. And so, in this guide, that's what we're gonna learn how to implement.

Now in order to do that, we first are gonna have to learn how to use the asset pipeline. So how we can add images into our project and then how we can pull them out and use them in the app. So I am going to give you if you go to the Show Notes of this guide, I'm gonna give you this image, it's the Memepedia logo here, and so you can go and download that and then follow along.

So I'm going to take that image and then if you open up your application in the file system, it's gonna look pretty much like this. Open up the Assets Directory and then go and just simply click and drag and move that logo into that Assets Directory. Once it's there, we can work with it.

large

Now, let's open up the File System here, and let's create a new directory and a new component. So in the Components Directory, I'm gonna right-click, click New File and I'm gonna call this our Images Directory, and let's just call this HeaderLogo.tsx. And confirm that this was added to the right directory and it was.

So the reason why we're doing this is because whenever you're using images in React Native, you can't simply work with them the same way that you work with them in say a React web application. You're gonna have to go through a few more steps in order to get them set up properly. Because remember, the entire point of using React Native is this code is going to compile down into native code that your phone can actually work with. And so because of that, we also have to set up a few configuration items ourselves.

So we're gonna start by importing React from React just like we always do in any component. Then we're gonna use the image component provided by React Native. So I'm gonna say import and then in curly brackets, we'll say image from react-native and then once we have that, now we can create our export statement. So I'll say export default and then inside of here, we're simply going to return the image tag. So here I'm going to say image and now if you look at the image prop, so if you go to the React Native documentation and look at the image component props, then you'll see that we are missing a few required ones right here.

So if you hover over it, you can see we have a little bit of guidance.

large

It takes a little while, whenever you're working with TypeScript, especially if you're new to it and new to using it in React applications, it can take a little bit of time to get used to reading these warnings. So let's take a little bit of time and actually work through that. So a few of these are confusing where it says no overload matches this call, Overload one of two, props image gave the following error.

This is where it's telling us what we need to do and it's actually guiding us along how we should work with this component. It says that the property source is missing in the type but it's required. So that's telling us that there is a property for this image tag called source. So we can come in here and we can say source and now we can provide that source.

So source is looking for a couple of different items, there are a few options. One, you can provide a URL which they call a URI. So if you're pulling this image from the web which we are gonna do that later on when we get into calling the API; when you're doing that, you can pass into source an object and you can say URI and then you can say imagine we're working with like a post or something and you could say post.image_url, something like that.

HeaderLogo.tsx

export default () => {
  return <Image source={{uri: post.image_url}} />
}

That is one way to work with the image tag. We're not gonna work with it that way though right now because we actually don't need a URI, we're not pulling this from the web, we're pulling this directly from our application's asset pipeline. So because of that, we have another option which is to use what's called a require statement.

So I'm gonna say require and then require takes a string argument and this is gonna be a path to wherever the image is. I'm gonna say require ../../assets/ and then you'll need the exact name including the extension. So I'm just gonna go copy that and so let me open that up, copy the full name and extension and then just paste that in and then hit Save.

HeaderLogo.tsx

export default () => {
  return <Image source={require("../../assests/memipedia-logo.png")} />;
};

Now obviously we're not calling this yet so you're not gonna see anything on the screen but even if we were calling it, I'm gonna give you a little hint and tell you you still wouldn't see it on the screen, you just see a little empty space. And that's because images just like the view tag, the view component in React Native, have to be told what their height is. So if you do not provide a height to this image tag, then you are not going to be seeing anything at all and that can lead to some very confusing bugs whenever you're building out your application. So I wanted to make that clear right here.

Before we do this and before we add some image styles, let's actually refactor this and make this require statement a variable just because I don't really like these lines getting that long because they get harder to read. So I'm gonna come up above the export statement and I'm just gonna say const and I'm just gonna say img or let's just say imgPath or you could call logoPath, anything you want, anything that makes sense. And there, that's where I'm gonna put the require statement. So I'm gonna put the entire require up here and now that I've done that, now I can simply call the image path there and that's going to work.

HeaderLogo.tsx

import React from "react";
import { Image } from "react-native";

const imgPath = require("../../assets/memipedia-logo.png");

export default () => {
  return <Image source={imgPath} />;
};

So that's one part, now let's add our height and our width. So I'm gonna go style so I'm just gonna use an inline style prop here. And that's gonna take an object as normal and let's give it a height and for the height, I played around with this one before, it's gonna be a height of 30 and it's gonna be a width of 29, so not a perfect square; so that's the reason for those sizes. So hit Save and our header logo is done.

HeaderLogo.tsx

export default () => {
  return <Image source={imgPath} style={{ height: 30, width: 29}} />;
};

Now it's time to call that. So if you open up the router, you can open it up, and right below where it says headerTintColor, we can give it another option and that option is gonna be the headerTitle, and headerTitle is a little bit different. We can't simply call our component, we actually have to call it as an anonymous function and you're gonna see this a lot in React and React Native and the reason is that when headerTitle gets called, React Native is going to then proactively call the function but we don't want it to happen too early. We want it to happen exactly when React Native wants it to happen because it has its own set of steps and its own way of understanding the best time to call these types of processes.

So to do an anonymous function, we're gonna just call the parens followed by a fat error function, and then we're going to use our header logo. So we haven't imported it yet but we can just call it. So I'm gonna say HeaderLogo, it doesn't take any props and it's gonna be a self-closing tag, and now we simply have to import that.

So let's come up to the top here and I'll say import the HeaderLogo from ../ and this is in the components and then in there it's in images and then HeaderLogo and we don't need the extension. So let's hit Save and let's see if that's going to work.

router.tsx

import React from "react";
import { createAppContainer, createSwitchNavigator } from "react-navigation";
import { createStackNavigator } from "react-navigation-stack";

import FeedScreen from "../screens/FeedScreen";
import SearchScreen from "../screens/SearchScreen";
import AccountScreen from "../screens/AccountScreen";
import PostFormScreen from "../screens/PostFormScreen";

import HeaderLogo from "../components/images/HeaderLogo";

import { dark } from "../styles/colors";

const AppStack = createStackNavigator(
  {
    Feed: FeedScreen,
    Search: SearchScreen,
    Account: AccountScreen,
    PostForm: PostFormScreen
  },
  {
    initialRouteName: "Feed",
    defaultNavigationOptions: {
      headerStyle: {
        backgroundColor: dark
      },
      headerTintColor: "#fff",
      headerTitle: () => <HeaderLogo />
    }
  }
);

And there you go, if you come up here at the top, it might be a little bit harder to see depending on the screen you're looking at, but there is our logo and it's looking great.

large

So you now have learned quite a bit in a relatively short period of time. Let's review really quick. One, you've learned how and where to put images when you want to work with local images in your application.

These are gonna be things like logos or anything that doesn't need to dynamically change. So you now know how to add those to that Asset Directory. Next, you know how to work with the image component in React Native. You know how to require a local image and then how to pass that to the image prop.

You also know how you can set the styles, and please remember, because this is gonna save you a lot of frustration, anytime you're working with an image component, you have to set a height or else you're not gonna see it. That's what we did here. And then lastly, you saw how we could work with the headerTitle component, how we can call any type of component that we wanna work with, call it as an anonymous function, and then you saw that all rendered right in the device.

Resources