FCC Speedrun -Recipe App -Tryst with Styled Components

Sharad Jain
Chingu
Published in
4 min readJan 27, 2019

If you don’t know about FCC speedrun then you can read about it here. This challenge was taken by our team as a project for chingu winter cohort. You can read the post about our first project here and second project here.

About the app

Recipe app is a take-home project on the freecode camp curriculum. This app is very similar to the ToDo app in the sense of complexity. So to add a little more constraint for our learning, we decided to implement backend service for storing/retrieving and modifying recipes.

Recipe app basically displays a list of recipes that you have. You can click on a recipe from the recipe navigator and it is displayed in the viewer. One can add delete current recipe by clicking on the delete button and add a new recipe by clicking on the + icon.

Screenshot from the demo app

Here is the link to our repo and live deployed app link.

Styled Components

We continued with our quest with independent react components and decided to give styled components a try as we had heard a lot about it.

Styled components library was very easy to set up with single node module to install.

npm install --save styled-components

Styled components brought our styling inside the component file itself and it became a lot easier and accessible to make changes to styles for a component. We no longer needed to jump between CSS file and js files any longer. Also, use of classes and id that were being specifically used for styled were not needed. Here is an example of an add button.

import React from "react";
import styled from "styled-components";

import { library } from "@fortawesome/fontawesome-svg-core";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faPlusCircle } from "@fortawesome/free-solid-svg-icons";

library.add(faPlusCircle);

const Button = styled(FontAwesomeIcon)`
font-size: 40px;
color: ${props => props.theme.secondary};
background: ${props => props.theme.textColor};
border-radius: 50%;
`;

const AddRecipeButton = props => {
return <Button icon="plus-circle" onClick={props.onClick} />;
};

export default AddRecipeButton;

With react we were separating components by their functionality but with styled components, we had to go a lot more granular where we had to separate out individual element tags if we wanted to give them styling. Like in below example, we had to create separate components for Title, TitleBar, RecipeBody, and Viewer.

const StyledRecipeViewer = styled.div`
background: ${props => props.theme.secondaryLight};
width: 100%;
flex-grow: 2;
max-height: 100vh;
overflow-y: scroll;
color: ${props => props.theme.textColor};
`;
const TitleBar = styled.div`
height: 10%;
background: ${props => props.theme.secondary};
padding-left: 1%;
text-align: center;
font-size: 3vw;
display: flex;
justify-content: flex-start;
align-items: center;
`;
const RecipeBody = styled.div`
padding: 20px;
`;

const RecipeTitle = styled.h2`
display: inline-block;
margin: 0;
padding-left: 5%;
font-size: 3vw;
`;

const RecipeViewer = ({
_id,
ingredients,
instructions,
name,
onDeleteClick
}) => {
return (
<StyledRecipeViewer>
<TitleBar>
<DeleteRecipeButton
onClick={() => {
onDeleteClick(_id);
}}
/>
<RecipeTitle>{name}</RecipeTitle>
</TitleBar>
<RecipeBody>
<div className={"instructions"}>
<h2>Ingredients:</h2>
<ul>{IngredientLists(ingredients)}</ul>
</div>
<div className={"instructions"}>
<h2>Instructions:</h2>
<p>{instructions}</p>
</div>
</RecipeBody>
</StyledRecipeViewer>
);
};

const IngredientLists = ingredients => {
if (ingredients && Array.isArray(ingredients)) {
return ingredients.map(ingredient => (
<li key={ingredient.replace(" ", "")}>{ingredient}</li>
));
}
};

export default RecipeViewer;

Testing Styled Components

As we had brought our component style and code together in a single file, it became necessary for us to monitor our styling changes as well with tests.

We used jest styled components — a library that allowed us to capture styling changes in snapshots. Also, we had to use react-test-renderer for our snapshot tests instead of enzyme shallow which did not capture styling in snapshot tests.

import React from "react";
import renderer from "react-test-renderer";
import AddRecipeButton from "./AddRecipeButton";

describe("Add Recipe Button", () => {
it("matches snapshot", () => {
const RecipeButtonWrapper = renderer
.create(<AddRecipeButton onClick={() => {}} />)
.toJSON();
expect(RecipeButtonWrapper).toMatchSnapshot();
});
});
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Add Recipe Button matches snapshot 1`] = `
.c0 {
font-size: 40px;
border-radius: 50%;
border: none;
}

<svg
aria-hidden="true"
className="svg-inline--fa fa-plus-circle fa-w-16 c0"
data-icon="plus-circle"
data-prefix="fas"
onClick={[Function]}
role="img"
style={Object {}}
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm144 276c0 6.6-5.4 12-12 12h-92v92c0 6.6-5.4 12-12 12h-56c-6.6 0-12-5.4-12-12v-92h-92c-6.6 0-12-5.4-12-12v-56c0-6.6 5.4-12 12-12h92v-92c0-6.6 5.4-12 12-12h56c6.6 0 12 5.4 12 12v92h92c6.6 0 12 5.4 12 12v56z"
fill="currentColor"
style={Object {}}
/>
</svg>
`;

If you observe we are now capturing styles inside our components itself. If you ask me, this is a big win for me with styled components as I am able to test both my code and styles with this.

We tried to solve some more problems with this project which I plan to share as individual posts like

  1. Structuring and deploying express server and react app in a single repo
  2. NPM pre and post hooks for install and test
  3. Creating react modals in react

If you liked this then here are links to other projects that we worked on

  1. Weather App
  2. Pomodoro Clock

--

--