# 7-3. Feed Component

![klaystagram-feed](/files/OEl1rWuBop3KIMMo49K3)

1. `Feed` component's role
2. Read data from contract: `getFeed` method
3. Save data to store: `setFeed` action
4. Show data in component: `Feed` component

## 1) `Feed` component's role <a href="#id-1-feed-component-s-role" id="id-1-feed-component-s-role"></a>

In chapter [4. Write Klaystagram Smart Contract](/content/dapp/tutorials/klaystagram/4.-write-klaystagram-smart-contract.md), we wrote `PhotoData` struct, and located it inside `_photoList` mapping. Feed component's role is as follows: 1. Read `PhotoData` via calling Klaystagram contract method (`redux/actions/photos.js`) 2. Show `PhotoData`(feed) with its owner information (`components/Feed.js`)

## 2) Read data from contract: `getPhoto` method <a href="#id-2-read-data-from-contract-getphoto-method" id="id-2-read-data-from-contract-getphoto-method"></a>

1. Call contract method: `getTotalPhotoCount()`

   If there are zero photos, call `setFeed` action with an empty array.
2. Call contract method:`getPhoto(id)`

   If there are photos, get each photo data as a promise and push it in the feed array. When all promises have resolved, return the feed array.
3. Call redux action: `setFeed(feed)`

   Get resolved feed array and save it to redux store.

```javascript
// src/redux/actions/photos.js

const setFeed = (feed) => ({
  type: SET_FEED,
  payload: { feed },
})

export const getFeed = () => (dispatch) => {
  // 1. Call contract method(READ): `getTotalPhotoCount()`
  // If there is no photo data, call `setFeed` action with empty array
  KlaystagramContract.methods.getTotalPhotoCount().call()
    .then((totalPhotoCount) => {
      if (!totalPhotoCount) return []
      const feed = []
      for (let i = totalPhotoCount; i > 0; i--) {
        // 2. Call contract method(READ):`getPhoto(id)`
        // If there is photo data, call all of them
        const photo = KlaystagramContract.methods.getPhoto(i).call()
        feed.push(photo)
      }
      return Promise.all(feed)
    })
    .then((feed) => {
      // 3. Call actions: `setFeed(feed)`
      // Save photo data(feed) to store
      dispatch(setFeed(feedParser(feed))
    })
}
```

## 3) Save data to store: `setFeed` action <a href="#id-3-save-data-to-store-setfeed-action" id="id-3-save-data-to-store-setfeed-action"></a>

After we successfully fetch photo data (feed) from the Klaystagram contract, we call `setFeed(feed)` action. This action takes the photo data as a payload and saves it in a redux store.

## 4) Show data in component: `Feed` component <a href="#id-4-show-data-in-component-feed-component" id="id-4-show-data-in-component-feed-component"></a>

```javascript
// src/components/Feed.js
import React, { Component } from 'react'
import { connect } from 'react-redux'
import moment from 'moment'
import Loading from 'components/Loading'
import PhotoHeader from 'components/PhotoHeader'
import PhotoInfo from 'components/PhotoInfo'
import CopyrightInfo from 'components/CopyrightInfo'
import TransferOwnershipButton from 'components/TransferOwnershipButton'
import { drawImageFromBytes} from 'utils/imageUtils'
import { last } from 'utils/misc'

import * as photoActions from 'redux/actions/photos'

import './Feed.scss'

class Feed extends Component {
  constructor(props) {
    super(props)
    this.state = {
      isLoading: !props.feed,
    }
  }

  static getDerivedStateFromProps = (nextProps, prevState) => {
    const isUpdatedFeed = (nextProps.feed !== prevState.feed) && (nextProps.feed !== null)
    if (isUpdatedFeed) {
      return { isLoading: false }
    }
    return null
  }

  componentDidMount() {
    const { feed, getFeed } = this.props
    if (!feed) getFeed()
  }

  render() {
    const { feed, userAddress } = this.props

    if (this.state.isLoading) return <Loading />

    return (
      <div className="Feed">
        {feed.length !== 0
          ? feed.map(({
            id,
            ownerHistory,
            data,
            name,
            location,
            caption,
            timestamp,
          }) => {
            const originalOwner = ownerHistory[0]
            const currentOwner = last(ownerHistory)
            const imageUrl = drawImageFromBytes(data)
            const issueDate = moment(timestamp * 1000).fromNow()
            return (
              <div className="FeedPhoto" key={id}>
                <PhotoHeader
                  currentOwner={currentOwner}
                  location={location}
                />
                <div className="FeedPhoto__image">
                  <img src={imageUrl} alt={name} />
                </div>
                <div className="FeedPhoto__info">
                  <PhotoInfo
                    name={name}
                    issueDate={issueDate}
                    caption={caption}
                  />
                  <CopyrightInfo
                    className="FeedPhoto__copyrightInfo"
                    id={id}
                    issueDate={issueDate}
                    originalOwner={originalOwner}
                    currentOwner={currentOwner}
                  />
                  {
                    userAddress.toUpperCase() === currentOwner.toUpperCase() && (
                      <TransferOwnershipButton
                        className="FeedPhoto__transferOwnership"
                        id={id}
                        issueDate={issueDate}
                        currentOwner={currentOwner}
                      />
                    )
                  }
                </div>
              </div>
            )
          })
          : <span className="Feed__empty">No Photo :D</span>
        }
      </div>
    )
  }
}

const mapStateToProps = (state) => ({
  feed: state.photos.feed,
  userAddress: state.auth.address,
})

const mapDispatchToProps = (dispatch) => ({
  getFeed: () => dispatch(photoActions.getFeed()),
})

export default connect(mapStateToProps, mapDispatchToProps)(Feed)
```

At the first time, you can only see the text "No photo :D" because there is no photo data in contract yet.\
Let's make a UploadPhoto component to send photo data to contract!


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://archive-docs.klaytn.foundation/content/dapp/tutorials/klaystagram/7.-feedpage/7-3.-feed-component.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
