React + Storyblok - Displaying Content

In my previous post on React + Storyblok, I showed you how to setup a basic React app and fetch some content from the Storyblok API. In this post we'll dive a bit deeper and see how we can parse multiple stories returned and display it as a repeating list of items in React. You could use this for a simple blog, or perhaps a small portfolio.

Creating the React View

We'll assume that you've already setup your React app, but if you haven't done that yet you might want to check out my previous post on that before moving ahead.

We'll be building from a bare-bones react application, so open your text editor and open App.tsx. You can go ahead and delete everything between the main div <div className="App" /> in the template. We'll be replacing that with our awesome Storyblok content.

To consume the Storyblok API the easiest, we're going to import the storyblok-js-client library along with the StoryData interface. We'll also need a place to store the Storyblok data in the App component state, so let's add useState from the already imported React library.

import React, { useState } from 'react'
import StoryblokClient, { StoryData } from 'storyblok-js-client'

At the top of the App function, setup your story state and add the StoryData[] typing to indicate the shape of the data we expect from the API. We will start the initial state with an empty array.

const [stories, setStories] = useState<StoryData[]>([])

Next, let's use the StoryblokClient to fetch some sweet sweet data.

At the top of the App function, add the following and replacing the "YOUR-PUBLIC-TOKEN" with your own from the Storyblok API tab within settings. I like to keep my token stored as an environment variable and access it like process.env.REACT_APP_STORYBLOK_TOKENso it doesn't get repeated everywhere in my templates. You will need to store this in an .env file but I'm not going to elaborate on that as it's outside the scope of this tutorial.

const Storyblok = new StoryblokClient({
    accessToken: "YOUR-PUBLIC-TOKEN",
    cache: {
      clear: "auto",
      type: "memory",
    },
  })

Below that add:

Storyblok.get('cdn/stories', {
    per_page: 4,
    page: 1,
  }).then(result => {
    setStories(result.data.stories)
  })

This will make the GET call to storyblok's API and retrieve a total of 4 items, then update the stories state with the response data. Your App.tsx file should now look something like this:

import React, { Fragment, useState } from 'react';
import './App.css';
import StoryblokClient, { StoryData } from "storyblok-js-client";

function App() {
  const [stories, setStories] = useState<StoryData[]>([]);

  const Storyblok = new StoryblokClient({
    accessToken: process.env.REACT_APP_STORYBLOK_TOKEN,
    cache: {
      clear: 'auto',
      type: 'memory',
    },
  })

  Storyblok.get('cdn/stories', {
    per_page: 4,
    page: 1,
  }).then(result => {
    setStories(result.data.stories);
    console.log('stories: ', stories);
  })

  return (
    <Fragment />
  )
}

export default App;

At this point, if you preview the code in your browser, you should see a network call sent to the Storyblok https://api.storyblok.com/v2/cdn/stories?per_page=4&page=1&version=published&token=YOUR-PUBLIC-TOKEN&cv=1643638226. Unless you already have some content saved in Storyblok, you should see it return an empty array. Let's fix that and create some content now in Storyblok.

Adding the Storyblok Content

If you haven't already, you'll need to sign up for a free Storyblok account. Once your account is created, I recommend starting by creating a new "Blank Space", that way we can start with the pure basics and add complexity later. Once your account is created, you'll want to create a new story under the "Getting Started" tab.

Click "Create Content" and choose "Add New" from the radios and call it "Demo" as the content type.

Next you'll want to define the fields used for this block. Let's use "Headline" as the field name, then choose "Add".


The default field is already a text field, but you can use many different types of fields with your blocks, image, rich text, markdown, link, table, to name a few.

For my text input, I'll choose to make it required and limit the characters to 38.

Save the field and you can now enter some text for your new Headline block and then publish the story.

For the sake of the tutorial, I've gone ahead and created two additional stories, all with the same Demo content type.

At this point you might be thinking this seems like a lot of work just to add a headline. In a real-world scenario, you would probably want to define a content type with multiple input fields and use that to describe a particular view of your website. An example would be:

  1. Create a new content type named "Portfolio"

  2. Add a plain text "Headline" field

  3. Add a rich text "Body" field

  4. Add multi-asset "Portfolio Images" field

So now that we have several stories created, let's go back now to our React app and see how we can output the content into our App.tsx template.

Displaying Storyblok in React

Modify your App.tsx template to match:

<Fragment>
  {stories.map((story) => (
    <div key={story.id}>{story.content.Headline}</div>
  ))}
</Fragment>

What this is doing is iterating over all the stories returned from the API, and outputting a <div /> element with the text content of the Headline field we created in Storyblok. Once you add that and save it, you should now see the headline printed out 3 times in your browser.

It doesn't look pretty at all but we can fix that very easily with some styling and page layout. We aren't going to focus on that in this tutorial though. Stay tuned for more React + Storyblok posts and we'll continue to dive deeper.