Klaytn Docs
Search…
7-3. Feed Component
klaystagram-feed
  1. 1.
    Feed component's role
  2. 2.
    Read data from contract: getFeed method
  3. 3.
    Save data to store: setFeed action
  4. 4.
    Show data in component: Feed component

1) Feed component's role

In chapter 4. Write Klaystagram Smart Contract, 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

  1. 1.
    Call contract method: getTotalPhotoCount()
    If there are zero photos, call setFeed action with an empty array.
  2. 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. 3.
    Call redux action: setFeed(feed)
    Get resolved feed array and save it to redux store.
1
// src/redux/actions/photos.js
2
3
const setFeed = (feed) => ({
4
type: SET_FEED,
5
payload: { feed },
6
})
7
8
export const getFeed = () => (dispatch) => {
9
// 1. Call contract method(READ): `getTotalPhotoCount()`
10
// If there is no photo data, call `setFeed` action with empty array
11
KlaystagramContract.methods.getTotalPhotoCount().call()
12
.then((totalPhotoCount) => {
13
if (!totalPhotoCount) return []
14
const feed = []
15
for (let i = totalPhotoCount; i > 0; i--) {
16
// 2. Call contract method(READ):`getPhoto(id)`
17
// If there is photo data, call all of them
18
const photo = KlaystagramContract.methods.getPhoto(i).call()
19
feed.push(photo)
20
}
21
return Promise.all(feed)
22
})
23
.then((feed) => {
24
// 3. Call actions: `setFeed(feed)`
25
// Save photo data(feed) to store
26
dispatch(setFeed(feedParser(feed))
27
})
28
}
Copied!

3) Save data to store: setFeed action

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

1
// src/components/Feed.js
2
import React, { Component } from 'react'
3
import { connect } from 'react-redux'
4
import moment from 'moment'
5
import Loading from 'components/Loading'
6
import PhotoHeader from 'components/PhotoHeader'
7
import PhotoInfo from 'components/PhotoInfo'
8
import CopyrightInfo from 'components/CopyrightInfo'
9
import TransferOwnershipButton from 'components/TransferOwnershipButton'
10
import { drawImageFromBytes} from 'utils/imageUtils'
11
import { last } from 'utils/misc'
12
13
import * as photoActions from 'redux/actions/photos'
14
15
import './Feed.scss'
16
17
class Feed extends Component {
18
constructor(props) {
19
super(props)
20
this.state = {
21
isLoading: !props.feed,
22
}
23
}
24
25
static getDerivedStateFromProps = (nextProps, prevState) => {
26
const isUpdatedFeed = (nextProps.feed !== prevState.feed) && (nextProps.feed !== null)
27
if (isUpdatedFeed) {
28
return { isLoading: false }
29
}
30
return null
31
}
32
33
componentDidMount() {
34
const { feed, getFeed } = this.props
35
if (!feed) getFeed()
36
}
37
38
render() {
39
const { feed, userAddress } = this.props
40
41
if (this.state.isLoading) return <Loading />
42
43
return (
44
<div className="Feed">
45
{feed.length !== 0
46
? feed.map(({
47
id,
48
ownerHistory,
49
data,
50
name,
51
location,
52
caption,
53
timestamp,
54
}) => {
55
const originalOwner = ownerHistory[0]
56
const currentOwner = last(ownerHistory)
57
const imageUrl = drawImageFromBytes(data)
58
const issueDate = moment(timestamp * 1000).fromNow()
59
return (
60
<div className="FeedPhoto" key={id}>
61
<PhotoHeader
62
currentOwner={currentOwner}
63
location={location}
64
/>
65
<div className="FeedPhoto__image">
66
<img src={imageUrl} alt={name} />
67
</div>
68
<div className="FeedPhoto__info">
69
<PhotoInfo
70
name={name}
71
issueDate={issueDate}
72
caption={caption}
73
/>
74
<CopyrightInfo
75
className="FeedPhoto__copyrightInfo"
76
id={id}
77
issueDate={issueDate}
78
originalOwner={originalOwner}
79
currentOwner={currentOwner}
80
/>
81
{
82
userAddress === currentOwner && (
83
<TransferOwnershipButton
84
className="FeedPhoto__transferOwnership"
85
id={id}
86
issueDate={issueDate}
87
currentOwner={currentOwner}
88
/>
89
)
90
}
91
</div>
92
</div>
93
)
94
})
95
: <span className="Feed__empty">No Photo :D</span>
96
}
97
</div>
98
)
99
}
100
}
101
102
const mapStateToProps = (state) => ({
103
feed: state.photos.feed,
104
userAddress: state.auth.address,
105
})
106
107
const mapDispatchToProps = (dispatch) => ({
108
getFeed: () => dispatch(photoActions.getFeed()),
109
})
110
111
export default connect(mapStateToProps, mapDispatchToProps)(Feed)
Copied!
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!