AWS Amplify Storage: React example for Avatar pictures
Tags: awsamplify, react
Published: 2020-04-09 19:06:51

After I described my expirience with AWS Amplify GraphQL APIs here I'd like to describe how I use AWS Amplify storage

{% link https://dev.to/johanneskonings/aws-amplify-api-graphql-queries-49b %} 

# AWS Amplify add storage

First I added the new storage category for images like it is decribed in the documentation.

https://docs.amplify.aws/lib/storage/getting-started?platform=js 

Two command are enough for the initial setup
```sh
amplify add storage
amplify push
```
# Usage in React

In my user profile page I had to add Storage to the imports. The configuration was already available through the categories Authentication and Analytcis.

```javascript
import Amplify, { Analytics, Auth, Storage } from "aws-amplify";
import awsconfig from "./../../aws-exports";
Amplify.configure(awsconfig);
```
The specific Storage configuration was one-liner. Because every user should have his own picture the access level is "private".

```javascript
Storage.configure({ track: true, level: "private" });
```
## Combination with Pinpoint 📈

In the storage configuration, `track: true` automatically enabled tracking of file operations in Pinpoint. Prerequisite is the category Analytics.

![pinpoint storage events](https://dev-to-uploads.s3.amazonaws.com/i/i9b0dejj0pirvdvzm753.png)

https://docs.amplify.aws/lib/storage/autotrack?platform=js

## Upload picture

To upload a picture I use this components. The img component open the file dialog and the input component upload the file.

```html
<a href="#">
    <input
        type="file"
        onChange={onProcessFile}
        ref={fileInput}
        hidden={true}
     />
</a>
 <img src={image} onClick={onOpenFileDialog} />
```

![before upload](https://dev-to-uploads.s3.amazonaws.com/i/n6mo9bgh3msbk3gkajwh.png)

The variable `fileInput` "connecting" the file dialog with the upload function.

```javascript
  let fileInput = React.createRef();

  const onOpenFileDialog = () => {
    fileInput.current.click();
  };

  const onProcessFile = e => {
    e.preventDefault();
    let reader = new FileReader();
    let file = e.target.files[0];
    try {
      reader.readAsDataURL(file);
    } catch (err) {
      console.log(err);
    }
    reader.onloadend = () => {
      setImage(reader.result);
    };
    Storage.put("profilePicture.png", file, {
      contentType: "image/png"
    })
      .then(result => console.log(result))
      .catch(err => console.log(err));
  };
```

![file dialog](https://dev-to-uploads.s3.amazonaws.com/i/zu6lbxff5nljlwgwx3n5.png)

After a picture is choosed via `Storage.put` the file will be uploaded to S3.

![s3](https://dev-to-uploads.s3.amazonaws.com/i/yhel2jesmmjf8zc6cudg.png)

With the the state image the picture is "transferred". Avatar is the placeholder if no profile picture was choosed.

```javascript
const [image, setImage] = useState(avatar);
```
![after upload](https://dev-to-uploads.s3.amazonaws.com/i/gkhv9ru1rfa0dqs0k1jc.png)


## Download picture

The profile picture will be downloaded every time the user profile page is called. With `Storage.get` there will always returned a signed url. Therefore the status must be checked if the image is available at all. That's discussed here: https://github.com/aws-amplify/amplify-js/issues/1145


```javascript
  useEffect(() => {
    onPageRendered();
  }, []);

  const onPageRendered = async () => {
    getProfilePicture();
  };

  const getProfilePicture = () => {
    Storage.get("profilePicture.png")
      .then(url => {
        var myRequest = new Request(url);
        fetch(myRequest).then(function(response) {
          if (response.status === 200) {
            setImage(url);
          }
        });
      })
      .catch(err => console.log(err));
  };
```

# Coding

{% github JohannesKonings/fff-badminton %}