Being inspired by a blog post from Dave Ceddia about learning while copying existing products, I came up with the idea of building a small story feed for the HackerNews page while trying out styled-components.
What will we build?
In this post, I will focus on building the components for one HackerNews story and the list which represents the feed. Future posts will handle the other topics like connecting the app to the HackerNews API.
The source code is available on GitHub but it might change since it is still a WIP. I try to keep this post up to date if something relevant changes in one of the components I present here.
Setting up the project
I’m going to assume that you already have your environment set up and installed node and npm, as well as create-react-app.
Now you can go ahead and generate the app by running the following command:
After the required packages have been downloaded and the app has been generated, you can run the project by running
npm start in the root folder of your generated app.
Since we want to try out styled-components, you have to install it with
npm install -S styled-components
The “Story” component
First of all, let’s start with the smallest part of the app: The list item which represents an entry / a story on HackerNews.
This component consists of several parts. I split it into a header and a footer, which may not be the right wording, but “content” also didn’t sound very good to me.
- Link to the source homepage
- User who posted the story
- A link to the original story on HackerNews to follow the discussion
And now comes the fancy part: Instead of cluttering the component with divs, spans and links and instead of creating a stylesheet containing different styles for a link in the footer and the title itself, we will create some styled-components instead and put them into the Header and Footer components.
Starting with the Header component, there will be a styled component for the rank, title and the link to the source homepage. It will get the rank, title and URL passed through props:
For brevity reasons I will not include the whole source code, but you can have a look on the complete source code on GitHub. Please note, that this is still a work in progress, so the code base might change slightly for future extensions of the project.
Basically, I put the child components of the header inside a wrapper component which is used as a flex container to arrange all elements inside it horizontally. Then I created a styled component for each of the above mentioned items and arranged them within HeaderWrapper.
Now take a closer look at the Title component, you can see that I was able to set the target property of the a tag to a new blank page just by calling the attrs function and passing the respective attribute.
From my point of view, shifting attributes to the creation of styled components and not having to map a class name of a style to a component leads to a more readable component structure later on in the Header or Footer components.
Similar to this, I created the Footer component:
As you can see, the time stamp is still just static text, since this will become a separate component which calculates the time passed since the story was posted and brings it in a format like “8 minutes ago”, “17 hours ago” or “3 days ago”. Nevertheless, creating such a component is not in the scope of this blog post.
Like the Header, this Footer component will get some information about the story passed through props and is again just a composition of different styled components.
Since the footer only consists of plain text and links, I only need a FooterLink component, which opens the given link in a new window (see the target attribute).
Now that we finished both the header and the footer, we can put them where they belong and finalize the Story component:
The “StoryList” component
Now that we created a component which represents one item in the list, we still need to build the list component to be able to display a bunch of stories.
The StoryList component will receive an array of stories to render a
<Story>once per item in the list. In this case, the rank will be calculated by the index of the item within the array since this will not be part of the story item we get from the API later.
Now we just have to use the
<StoryList> component somewhere in the app, and pass an array of HackerNews stories and it will render a list item for each of them. Since I did not use the API yet, I just used a static array with sample stories which I manually got from the API for the purpose of creating the basic components.
Since the App component is the root of the application, i also used it to define some global CSS rules. Styled-Components provides functionality to inject CSS globally, but they do only recommend to use it for styling the body or defining the font-face globally. (See injectGlobal)
As you can see, I retrieve my stories from my static API within componentWillMount and put them into the state. This will change as soon as the app will fetch new Stories from the API, which I will handle in a later blog post.
Now that everything is tied together, the app renders a list of a few HackerNews stories with a similar styling to the original HackerNews list.
What did I learn?
I did not yet fully discover and use every feature of styled-components, but as soon as I got the basic idea behind it, I was amazed of the positive effect of such little things like not having to add class names to components or having to maintain one big or multiple smaller CSS files instead of keeping the style as close to the component as possible.
It took some time until I got used to this (at least for me) different way of thinking, but once I got the hang of it, I wanted to make everything a styled component 🙂
This is my first ever blog post, so excuse me if something is not clear or I did not include enough material to keep it understandable. Also, if you read this, and stumble upon something which could have been solved better, please leave me a comment here, or contact me on Twitter as I appreciate every kind of feedback so I can not only improve my technical know how but also my writing 🙂