在react中,检查页面是否已刷新,然后关闭graphql查询的本地存储,否则保持当前本地存储的状态



我正试图建立一个基于用户点击的点击计数器。它会在用户每次单击时递增计数器。我正在使用react运行GatsbyJS。

我使用lambda函数将计数存储在faunadb中,因此每次单击按钮时它都会递增。这是有效的。

对于客户端,我使用localStorage更新组件hitCounter编号的状态,因此每次单击该按钮时,我都会更新localStorage。

所有这些都很有效。但是,如果我通过单击StoryBlock中的关闭按钮更改StoryPopFull的状态(见下面的代码(,并通过单击更多按钮重新打开,则该状态将保持localStorage状态,这是很好的。然而,如果我改变StoryPop的状态,关闭StoryGrid,重新打开SvgAnimation(命中计数器所在的组件(的所有状态,从graphQL查询中获取它,现在如果查询足够快,这就可以了,但lambda、faunadb和刷新页面之间大约有20秒的延迟,因为我没有使用graphql订阅,所以必须进行某种刷新。

有什么好的解决方案可以让用户在使用网站时使用localstorage来跟踪计数器,但当他们返回或刷新页面时(而不是重新加载组件(,我可以使用graphql查询更新localstorage。

到目前为止,这是我的代码,提前谢谢。

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

您是否尝试在查询完成后为设置函数?

const { loading, data } = useQuery(HIT_COUNTER, {
onCompleted({ findHitCounterByID }) {
window.localStorage.setItem('count', findHitCounterByID.amount);
}
});

这应该将localStorage数据设置为获取API响应后的任何响应。您可能需要调整它和代码中的其他内容,以确保它只在您希望的时候发生。为此,您可以考虑利用useLazyQueryuseEffect,仅在组件首次装载时调用此查询。

像这样的

const fetchHitCounter = useLazyQuery(HIT_COUNTER, {
onCompleted({ findHitCounterByID }) {
window.localStorage.setItem('count', findHitCounterByID.amount);
}
});
useEffect(() => {
fetchHitCounter();
}, []);

我认为您现在遇到的唯一问题是检测页面是否已刷新。因此,如果你能够检测到刷新,你可以对刷新采取适当的操作,我建议你看看这个问题:

检测刷新

因此,一旦你能够检测到刷新,你就可以在你的存储中添加一个标记,表明这一点,并采取你想要的行动。

最新更新