I am attempting to build a hit counter that is based off of a user click. It increments the counter each time the user clicks. I am running GatsbyJS with react.
I am using a lambda function to store the count in faunadb, so it increments each time the button is clicked. This is working.
For the client side I am updating the state of the component hitCounter number by using localStorage, so each time the button is clicked I update localStorage.
All of this works pretty well. However if I change the state of StoryPopFull
(seen in code below) by clicking the close button in StoryBlock
and reopen by clicking the more button the state keeps the localStorage state which is good. However If I change the state of StoryPop
closing the StoryGrid
reopen everything the state of SvgAnimation
(component where the hit counter lives) is taking it from the graphQL query, now this would be fine if the query came fast enough, but there is about a 20 second delay between the lambda, faunadb and hitting refresh on the page, because I am not using graphql subscriptions so there has to be a refresh of a kind.
What is a good solution so that while the user is using the site localstorage is used to track the counter, but when they return or refresh the page (not a component reload) I can update localstorage with the graphql query.
Here is my code thus far, thanks ahead of time.
import React, { useState, useEffect } from 'react';
import { Link } from "gatsby"
import Layout from "../components/layout"
import { gql } from "apollo-boost"
import { useQuery } from "@apollo/react-hooks"
import rabbit from "../images/rabbit.svg"
import { StoryBlock, StoryGrid, Svg } from "../components/indexStyles"
class SvgAnimation extends React.Component {
constructor(props) {
super(props)
let initialCount = Number(window.localStorage.getItem('count') || 0)
this.state = {
buttonDisabled: false,
hitCounter: initialCount,
}
this.handleCLick = this.handleCLick.bind(this);
}
componentDidMount(){
const {data} =this.props
window.localStorage.setItem('count', data.findHitCounterByID.amount)
}
async handleCLick(e) {
const {count, loading, data} =this.props
if(this.state.fillAnimate > 0){
try{
const response = await fetch("/.netlify/functions/hitCounter", {
method: "POST",
body: JSON.stringify({test:"test"}),
})
if (!response.ok) {
console.log(response);
}
else{
console.log("succes");
}
} catch(e){ console.log(e)}
let initialCount1 = Number(window.localStorage.getItem('count') || 0)
window.localStorage.setItem('count', initialCount1 +1)
let initialCount = Number(window.localStorage.getItem('count') || 0)
this.setState({ hitCounter: initialCount })
}
}
render() {
const { buttonDisabled, hitCounter } = this.state;
return (
<>
<button disabled={buttonDisabled} onClick={e => { this.handleCLick(e) }}>I want this</button>
<Svg aria-labelledby="title" id="svg" viewBox="0 0 100 125" xmlns="http://www.w3.org/2000/svg">
...
</Svg>
<span>{hitCounter}</span>
</>
)
}
}
const HIT_COUNTER = gql`
query HitCounter{
findHitCounterByID(id: "264173443862233609") {
amount
}
}
`
const IndexPage = () => {
const [StoryPop, setStoryPop] = useState(false);
const [StoryPopFull, setStoryPopFull] = useState(false);
const { loading, data } = useQuery(HIT_COUNTER);
const rabbitClick = (e) => {
setStoryPop(true)
}
const storyClick = (e) => {
setStoryPopFull(true)
}
const clickClose = (e) => {
setStoryPopFull(false)
}
const clickCloseStoryGrid = (e) => {
setStoryPop(false)
setStoryPopFull(false)
}
return (
<Layout>
<img onClick={(e => { rabbitClick(e) })} onMouseOut={e => { imageHoverOut(e) }} src={rabbit} />
{StoryPop &&
<StoryGrid >
<button onClick={e => { clickCloseStoryGrid(e) }}>Close</button>
<button onClick={e => { storyClick(e) }}>More</button>
</StoryGrid>
}
{StoryPopFull &&
<StoryBlock>
<button onClick={e => { clickClose(e) }}>Close</button>
<SvgAnimation count={data.findHitCounterByID.amount} data={data} loading={loading} />
</StoryBlock>
}
</Layout>
)
}
export default IndexPage