Almost EVERYONE who tried headless systems said they saw benefits. Download the state of CMS now!

Storyblok now on AWS Marketplace: Read more

O’Reilly Report: Decoupled Applications and Composable Web Architectures - Download Now

Empower your teams & get a 582% ROI: See Storyblok's CMS in action

Skip to main content

Building a blog app using React Native and Storyblok backend

Try Storyblok

Storyblok is the first headless CMS that works for developers & marketers alike.

  • Home
  • Tutorials
  • Building a blog app using React Native and Storyblok backend

Storyblok is a headless CMS (Content Management System) that provides a user-friendly interface for managing and delivering content across multiple platforms. It allows you to create and organize your blog posts, define custom content types, and easily retrieve the content through its RESTful API. 

React Native, a popular JavaScript framework for building mobile applications, provides an excellent solution for creating a mobile-friendly blog using JavaScript. 

In this tutorial, I'll guide you through building a blog reader app using React Native, with Storyblok as the backend CMS. Whether you're creating a standalone blog application or adding a blog to an existing React Native project, this tutorial is for you. 

Should you need to check out the end product of this tutorial in advance, here’s a preview link for the expo-go app. 

Section titled Prerequisites Prerequisites

To follow along with this tutorial, you should have some working knowledge of React Native as well as how an API works. Pre-existing familiarity with the Storyblok API could prove useful, although not required.  Let's get started!

Section titled Setting Up a Storyblok Instance   Setting Up a Storyblok Instance  

To get started, we’ll set up a Storyblok instance by creating an account and following the provided prompts to create a demo space. 

Storyblok demo space

Once set up, the demo space contains different content types for different use cases. Our focus in this tutorial is the Articles folder. 

Section titled Frontend Setup Frontend Setup

In this section, we’ll setup a React Native scaffold, add routing support, and design a basic blog app using React native stylesheets.

To get started, scaffold a react native project using expo and run the app in an iOS Simulator.

        
      npx create-expo-app RNblog
npx expo start --ios
    

Section titled Setting up Expo router Setting up Expo router

Next, Install the expo router package along with it’s required dependencies

        
      npx expo install expo-router react-native-safe-area-context react-native-screens expo-linking expo-constants expo-status-bar react-native-gesture-handler
    

Once installed, replace the content of your project’s index.js file with the following and make sure it’s referenced as your entry file in your package.json file.


        
      // index.js
import "expo-router/entry"; 
    

        
      //package.json
{
  "main": "index.js"
}
    

Once both files are set up, add the expo-router/babel plugin to your babel.config.js file and restart your project. 

        
      //babel.config.js
module.exports = function (api) {
  api.cache(true);
  return {
    presets: ["babel-preset-expo"],
    plugins: [require.resolve("expo-router/babel")],
  };
};
    

Next, restart your expo project in the terminal

        
      npx expo start --clear 
    

Section titled Designing the UI Designing the UI

Now that we have routing support enabled let’s build a simple UI for our blog application. 

Firstly, create an app/index.js file in your project’s root to create the following components.

  • A HomeScreen component containing a FlatList to house everything in our blog
  • An ArticleCard component to render each article from our blog
  • An RenderEmpty component as  a placeholder when there are no articles to display yet
  • A RenderHeader component to serve as our blog’s header
            
          // app/index.js
    
    // WIll be rendered when articles are yet to load
    const RenderEmpty = () => (
      <View style={styles.emptyStateView}>
        <Text style={styles.description}>
          {"Sit tight user, articles will show up here once they're fetched"}
        </Text>
      </View>
    );
    
    // Will be shown at the top of our articles list
    const RenderHeader = () => (
      <View style={styles.headerContainer}>
        <Text style={styles.title}> Welcome to RN Blog</Text>
        <Text>
          {"Here, you'll find a lot of stuff that contains stuff about a lot of stuff.
          You could almost say it's a blog for stuff"}
        </Text>
      </View>
    );
    
    // Article card component 
    const ArticleCard = ({ title, description, published_at }) => {
      return (
        <View style={styles.container}>
          <Text style={styles.title}>{title}</Text>
          <Text style={styles.date}>{published_at}</Text>
          <Text style={styles.description}>{description}</Text>
        </View>
      );
    };
    
    
    // HomeScreen component
    export default function HomeScreen() {
      return (
        <View style={styles.pageContainer}>
          <FlatList
            ListEmptyComponent={RenderEmpty}
            data={articles}
            showsVerticalScrollIndicator={false}
            ListHeaderComponent={
              <View style={styles.headerContainer}>
                <Text style={styles.title}> Welcome to RN Blog</Text>
                <Text>
                  Here, you'll find a lot of stuff that contains stuff about a lot
                  of stuff. You could almost say it's a blog for stuff
                </Text>
              </View>
            }
            renderItem={({ item }) => {
              return (
                <ArticleCard
                  title={item.name}
                  published_at={item.published_at}
                  description={item.content.teaser}
                />
              );
            }}
          />
        </View>
      );
    }
        

Section titled Adding Styling Adding Styling

At this point, our app doesn’t look very pleasant to the eye. Let’s fix that by adding some styling. 

Create a styles.js in your app/ folder with the following content.

        
      
// app/index.js 

import { StyleSheet } from "react-native";
 export const styles = StyleSheet.create({
  pageContainer: {
    paddingHorizontal: 20,
  },
  headerContainer: {
    marginTop: 40,
    marginBottom: 20,
    paddingHorizontal: 20,
    borderRadius: 8,
    backgroundColor: "red",
    paddingVertical: 20,
  },
  emptyStateView: {
    alignItems: "center",
  },
  container: {
    marginVertical: 20,
  },
  title: {
    fontSize: 24,
    marginVertical: 5,
    fontWeight: "600",
  },
  description: {
    fontSize: 16,
    fontWeight: "400",
  },
  date: {
    fontSize: 13,
    color: "grey",
  },
});
    

You should see the result on your mobile device or simulator.

Section titled Fetching blogs from our backend  Fetching blogs from our backend 

Like most REST APIs, Storyblok API can be accessed with traditional API clients like axios and fetch In this tutorial, however,  we’d prefer to use the Storyblok JS client as it has a host of built-in functionality to make working with Storyblok API a breeze. One such is the richTextResolver utility, which we’ll be making use of later in this guide. 

        
      npx expo install storyblok-js-client
    

Once Installed, we can set up an Instance of the Storyblok client in our index.js file with an access token from your dashboard. 

        
      const Storyblok = new StoryblokClient({
  accessToken: "<YOUR TOKEN HERE>",
});
    

To fetch the content of a folder from our backend, we pass the story name as such

        
      Storyblok.getAll("cdn/stories", {
      starts_with: "articles/",
    })
      .then((response) => {
        console.log("RESPONSE", response);
      })
      .catch((error) => {
        console.log(error);
      });
    

We can see here a list of the sample data created in our dummy space and that each element in our posts array contains the properties: name, published_at, headline, and teaser

Now that we have successfully fetched data from our backend let’s modify our HomeScreen component to render content from our Storyblok backend. To do so, let’s use the useEffect hook from React.

        
      const [articles, setArticles] = useState([]);
  useEffect(() => {
    Storyblok.getAll("cdn/stories", {
      starts_with: "articles/",
    })
      .then((response) => {
        setArticles(response);
        const s = Storyblok.richTextResolver.render(response[2].content.text);
        console.log(s);
      })
      .catch((error) => {
        console.log(error);
      });
  }, []);
    

On saving the changes, our app should now display the listing of articles fetched from our Storyblok backend. 


Section titled Conclusion Conclusion

So far, we explored the process of building a blog app using React Native and integrating with Storyblok on the backend. We started by setting up a storybook account and setting

We then moved on to scaffolding the React Native app, adding navigation support using the expo router, and designing the UI.  Finally, we fetched real data from the Storyblok-powered API and implemented features to fetch all articles and display a single article

Now that you have the foundation building, you can explore additional features and enhancements. Consider implementing features like search functionality, user authentication, and commenting functionality. Additionally, you can dive deeper into some of Storyblok's capabilities, such as managing images and assets, multilingual content, and version control.

Author

Oluwaseun Raphael Afolayan

Oluwaseun Raphael Afolayan

Raphael is a Fullstack Software Engineer and Technical Writer passionate about building products to solve problems for users. Currently serving as CTO at Mytherapist.ng, a leading teletherapy platform for Nigerians.