Building a basic photo album in React
Tags: javascript, webdev
Published: 2021-10-20 01:54:09

## Purpose
I've loved taking pictures since I was little, but I don't really have a place to show off the best pictures I've taken. I decided to build myself a little photo gallery using React for the frontend, and a very simple JSON Server based backend.

## Basic Features
For my photo gallery, I broke the required features down to the basics:

* Display images in a gallery format
* Display an individual image
* Add an image to the gallery
* Edit the image's description
* Delete the image if needed

To those, I added a couple additional features:
* Mark images a "favorites"
* Display favorite images in a second gallery

## What I Used
To get to my basic feature set, I decided to use:
* [Create React App](https://github.com/facebook/create-react-app) to scaffold out the basic React boilerplate
* [React Router](https://github.com/remix-run/react-router) for routing within the app
* [Styled Components](https://styled-components.com/) to style the application
* [JSON Server](https://www.npmjs.com/package/json-server) as a backend for this minimum version of my app.

## Building the App
The photo gallery has four major components, which each have their own Routes:
* _Gallery_, which displays image thumbnails in a grid and links to individual _ImageDetails_: "/images" or "/favorites"
* _ImageDetails_, which displays a larger version of a selected image, along with the image description: nested under the gallery paths - "/images/<imageId>" or "/favorites/<imageId>"
* _ImageDetailsEdit_, which provides a way to edit the description of an image: nested under the image detail paths - "/images/<imageId>/edit" or "/favorites/<imageId>/edit"
* _NewImage_, which contains a form and the functions needed to add new images to the gallery: "/new"

Within and surrounding these components, I created a number of additional components to style the contents of each page and provide additional functionality. The majority of the components I created this way were Styled Components.

## Challenges
This was the first time I'd used Styled Components in a meaningful way. In the past, I've used a single stylesheet and classes to apply styles, but I wanted to challenge myself to something new. 

My first thought when reading the [documentation](https://styled-components.com/) was to wonder about the use of sting literals I hadn't encountered much before. If you haven't seen a styled component component before, it looks something like this:

```js
import styled from "styled-components";

const DetailCard = styled.div`
  display: grid;
  grid: "p i n" auto ". d ." auto / min-content 1fr min-content;
  max-width: 800px;
  margin: 0 auto;
`;
```

Breaking this down:  
`styled` is the default export from the `styled-components` module.

`div` is a function property of the `styled` object.

> A function? But where are the parentheses?

Notice that the CSS styles themselves are contained within the backticks (\`\`) of an ES6 [template literal](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals). In this case, it is a _tagged_ template literal. The tag of a tagged template literal is a function (here, `div`) that takes an array of strings as its first argument, and the values of any substitutions (indicated by the `${}` syntax in a template literal) as additional arguments.

This means the example above could be rewritten as the below, with no change in functionality:
```js
const DetailCard = styled.div([
  `
  display: grid;
  grid: "p i n" auto ". d ." auto / min-content 1fr min-content;
  max-width: 800px;
  margin: 0 auto;
`,
]);
```

Things get a bit more complicated when you introduce those substitutions. For example, with styled components, you can use props to change a component's styles:
```js
const NavButton = styled.button`
  grid-area: ${(props) => props.area};
  padding: 0 1rem;
`;
```
This allows us to pass in an area prop to define where the component will display:
```jsx
<NavButton area="n">Next</NavButton>
```
And translates to CSS like this:
```css
  grid-area: n;
  padding: 0 1rem;
```

This would be equivalent to, but much less convenient than, calling the `button` function property of `styled` directly:
```js
const NavButton = styled.button(
  ['grid-area: ','; padding: 0 1rem;'],
  (props) => props.area);
``` 

Once I was able to wrap my head around what this syntax meant, it was much easier to use styled components.

### Styled Component Tips:
* Don't be afraid of making a lot of styled components, as long as they each serve a purpose!
* Keep single-use components near where you use them. I kept mine in the same file as the component I used them in.
* If you find yourself using the same (or similar) styles or components in multiple places, you can pull the styled component into its own file and reuse it! Don't repeat yourself if you don't have to!
* Read the documentation
* Read this (Josh W Comeau Article on Styled Components in React)[https://www.joshwcomeau.com/css/styled-components/]. I found it very helpful, especially the section on making sure you have a single source of styles for each component.

## Plans for the future
As I have time, I'm planning to implement:
* Basic login and user validation
* Real photo upload instead of url submissions
* Additional albums
* Server-side photo resizing

## Visit the most recent version of the site
You can see a working version of the site at: https://photo-album.joedietrich.dev