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

  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

Trong chương 4. Soạn hợp đồng thông minh Klaystagram, 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

  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.

// 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

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

// 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!

Last updated