apollo+react实战项目 stepbystep(六)
为链接添加投票功能
1、添加投票组件
组件功能:
为链接添加索引:使用LinkList中的links.map(link,index)使用index为各个链接添加索引
添加一个投票标志:当用户登陆的情况下显示投票标志,当用户点击投票标志的时候,票数增加1,每个用户仅可为一个链接投一票
链接下显示:投票票数(link.votes),链接创建人(link.postBy.name),链接创建时间(createdAt)。
export default class Link extends React.Component{
render(){
const authToken=localStorage.getItem(AUTH_TOKEN)
return(
<div className="flex mt2 items-start">
<div className="flex items-center">
<span className="gray">{this.props.index+1}</span>
{authToken&&(
<div
className="ml1 gray f11"
onClick={voteMutation}
>▲</div>
)
}
</div>
<div className="ml1">
<div>
{this.props.link.description}({this.props.link.url})
</div>
<div className="f6 lh-copy gray">
{this.props.link.votes.length}| by{' '}
{this.props.link.postedBy?this.props.link.postedBy.name:'unknown'}{' '}
{timeDifferenceForDate(this.props.link.createdAt)}
</div>
</div>
</div>
);
}
}
其中timeDifferenceForDate实现的是根据一个时间点显示友好的间隔提示,我们在src/utils.js中定义
function timeDifference(current, previous) {
const milliSecondsPerMinute = 60 * 1000
const milliSecondsPerHour = milliSecondsPerMinute * 60
const milliSecondsPerDay = milliSecondsPerHour * 24
const milliSecondsPerMonth = milliSecondsPerDay * 30
const milliSecondsPerYear = milliSecondsPerDay * 365
const elapsed = current - previous
if (elapsed < milliSecondsPerMinute / 3) {
return 'just now'
}
if (elapsed < milliSecondsPerMinute) {
return 'less than 1 min ago'
} else if (elapsed < milliSecondsPerHour) {
return Math.round(elapsed / milliSecondsPerMinute) + ' min ago'
} else if (elapsed < milliSecondsPerDay) {
return Math.round(elapsed / milliSecondsPerHour) + ' h ago'
} else if (elapsed < milliSecondsPerMonth) {
return Math.round(elapsed / milliSecondsPerDay) + ' days ago'
} else if (elapsed < milliSecondsPerYear) {
return Math.round(elapsed / milliSecondsPerMonth) + ' mo ago'
} else {
return Math.round(elapsed / milliSecondsPerYear) + ' years ago'
}
}
export function timeDifferenceForDate(date) {
const now = new Date().getTime()
const updated = new Date(date).getTime()
return timeDifference(now, updated)
}
2、添加投票功能
mutation:
const VOTE_MUTATION=gql`
mutation VoteMutation($linkId: ID!) {
vote(linkId: $linkId) {
id
link {
votes {
id
user {
id
}
}
}
user {
id
}
}
}
`
在投票按钮上 ▲添加Mutation组件
{authToken&&(
<Mutation
mutation={VOTE_MUTATION}
variables={{linkId:this.props.link.id}}
update={(store, { data: { vote } }) =>
this.props.updateStoreAfterVote(store, vote, this.props.link.id)
}
>
{
voteMutation=>(
<div
className="ml1 gray f11"
onClick={voteMutation}
>▲</div>
)
}
</Mutation>
)}
3、实时更新
我们希望用户投票后可以立刻看到投票结果,因此我们需要手工更新一下缓存,否则的话只有在刷新页面的时候才会向服务器请求更新缓存然后更新。
update接受缓存cache为第一个参数,然后是{data,loading,error}这里我们根据投票结果和链接id回调上一级的updateStoreAfterVote函数
在LinkList.js组件中:
export default class LinkList extends React.Component{
_updateCacheAfterVote = (store, createVote, linkId) => {
const data = store.readQuery({ query: FEED_QUERY })
const votedLink = data.feed.links.find(link => link.id === linkId)
votedLink.votes = createVote.link.votes
store.writeQuery({ query: FEED_QUERY, data })
}
render(){
return(
<Query query={FEED_QUERY}>
{
({ loading, error, data })=>{
if(loading) return <div>loading</div>
if(error) return <div>Error</div>
const links = data.feed.links
return(
<div>
{links.map((link,index)=>(<Link
key={link.id}
link={link}
index={index}
updateStoreAfterVote={this._updateCacheAfterVote}
/>))}
</div>
)
}
}
</Query>
);
}
}
更新缓存的步骤:
(1)、读取缓存数据
(2)、更新读取的缓存数据
(3)、将更新的缓存数据写入缓存。
现在只要我们进行投票,便可以看到投票结果了。
4、创建链接时实时更新
<Mutation
mutation={POST_MUTATION}
variables={{ description, url }}
onCompleted={() => this.props.history.push('/')}
update={(store, { data: { post } }) => {
const data = store.readQuery({ query: FEED_QUERY })
data.feed.links.unshift(post)
store.writeQuery({
query: FEED_QUERY,
data
})
}}
>
{postMutation => <button onClick={postMutation}>Submit</button>}
</Mutation>
浙公网安备 33010602011771号