# 7-3. Thành phần nguồn cấp dữ liệu

![klaystagram-feed](/files/1ajywQrwvlwxLp0sBCy2)

1. Vai trò của thành phần `Feed`
2. Đọc dữ liệu từ hợp đồng: phương pháp `getFeed`
3. Lưu dữ liệu vào cửa hàng: hàm `setFeed`
4. Thể hiện dữ liệu trong thành phần: thành phần `Feed`

## 1) Vai trò của thành phần `Feed` <a href="#id-1-feed-component-s-role" id="id-1-feed-component-s-role"></a>

Trong chương [4. Soạn hợp đồng thông minh Klaystagram](/content/dapp/tutorials/klaystagram/4.-write-klaystagram-smart-contract.md), ta đã viết cấu trúc `PhotoData` và đặt nó trong ánh xạ `_photoList`. Vai trò của thành phần Feed như sau: 1. Đọc `PhotoData` thông qua gọi phương pháp hợp đồng Klaystagram (`redux/actions/photos.js`) 2. Thể hiện `PhotoData`(nguồn cấp dữ liệu) với thông tin của chủ sở hữu (`components/Feed.js`)

## 2) Đọc dữ liệu từ hợp đồng: phương pháp `getPhoto` <a href="#id-2-read-data-from-contract-getphoto-method" id="id-2-read-data-from-contract-getphoto-method"></a>

1. Gọi phương pháp hợp đồng: `getTotalPhotoCount()`

   Nếu không có ảnh, hãy gọi hàm `setFeed` với một mảng trống.
2. Gọi phương pháp hợp đồng: `getPhoto(id)`

   Nếu có ảnh, lấy dữ liệu mỗi ảnh làm promise và đẩy nó vào mảng nguồn cấp dữ liệu. Khi tất cả promise đã được xử lý, quay lại mảng nguồn cấp dữ liệu.
3. Gọi hoạt động redux: `setFeed(feed)`

   Lấy mảng nguồn cấp dữ liệu đã xử lý và lưu vào cửa hàng redux.

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

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

export const getFeed = () => (dispatch) => {
  // 1. Gọi phương pháp hợp đồng(READ): `getTotalPhotoCount()`
  // Nếu không có dữ liệu ảnh, hãy gọi hàm `setFeed` với mảng trống
  KlaystagramContract.methods.getTotalPhotoCount().call()
    .then((totalPhotoCount) => {
      if (!totalPhotoCount) return []
      const feed = []
      for (let i = totalPhotoCount; i > 0; i--) {
        // 2. Gọi phương pháp hợp đồng(READ):`getPhoto(id)`
        // Nếu có dữ liệu ảnh, hãy gọi tất cả
        const photo = KlaystagramContract.methods.getPhoto(i).call()
        feed.push(photo)
      }
      return Promise.all(feed)
    })
    .then((feed) => {
      // 3. Gọi hàm: `setFeed(feed)`
      // Lưu dữ liệu ảnh(nguồn cấp dữ liệu) vào cửa hàng
      dispatch(setFeed(feedParser(feed))
    })
}
```

## 3) Lưu dữ liệu vào cửa hàng: hành động `setFeed` <a href="#id-3-save-data-to-store-setfeed-action" id="id-3-save-data-to-store-setfeed-action"></a>

Sau khi tìm nạp thành công dữ liệu ảnh (nguồn cấp dữ liệu) từ hợp đồng Klaystagram, ta gọi hành động `setFeed(feed)`. Hành động này lấy dữ liệu ảnh làm tải trọng và lưu vào cửa hàng redux.

## 4) Hiển thị dữ liệu trong thành phần: thành phần `Feed` <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">Không có ảnh :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)
```

Ở lần đầu tiên, bạn chỉ có thể thấy lời nhắn "Không có ảnh :D" vì chưa có dữ liệu ảnh trong hợp đồng.\
Hãy tạo một thành phần UploadPhoto để gửi dữ liệu ảnh đến hợp đồng!


---

# 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-vn.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.
