在反应中检查页面是否已刷新然后将 localstorage 设置为关闭 graphql 查询否则保持当前本地存储状态
In react check if page has refreshed then set localstorage off of graphql query otherwise keep current local storage for state
我正在尝试建立一个基于用户点击的点击计数器。每次用户点击它都会增加计数器。我是 运行 有反应的 GatsbyJS。
我正在使用 lambda 函数将计数存储在 faunadb 中,因此每次单击按钮时它都会递增。这是工作。
对于客户端,我正在使用 localStorage 更新组件 hitCounter 编号的状态,因此每次单击按钮时我都会更新 localStorage。
所有这些都很好用。但是,如果我通过单击 StoryBlock
中的关闭按钮更改 StoryPopFull
的状态(在下面的代码中看到)并通过单击更多按钮重新打开,状态将保持 localStorage 状态,这很好。但是,如果我更改 StoryPop
的状态,关闭 StoryGrid
重新打开所有内容, SvgAnimation
(命中计数器所在的组件)的状态正在从 graphQL 查询中获取它,现在就可以了如果查询速度足够快,但是在 lambda、faunadb 和点击页面刷新之间大约有 20 秒的延迟,因为我没有使用 graphql 订阅,所以必须有某种刷新。
什么是好的解决方案,以便在用户使用站点时使用本地存储来跟踪计数器,但是当他们 return 或刷新页面(不是组件重新加载)时,我可以更新本地存储graphql 查询。
这是我到目前为止的代码,提前致谢。
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 响应在获取后的任何内容。您可能需要调整它和代码中的其他内容,以确保它只在您需要时发生。为此,您可以考虑利用 useLazyQuery
和 useEffect
仅在您的组件首次安装时调用此查询。
像这样
const fetchHitCounter = useLazyQuery(HIT_COUNTER, {
onCompleted({ findHitCounterByID }) {
window.localStorage.setItem('count', findHitCounterByID.amount);
}
});
useEffect(() => {
fetchHitCounter();
}, []);
我正在尝试建立一个基于用户点击的点击计数器。每次用户点击它都会增加计数器。我是 运行 有反应的 GatsbyJS。
我正在使用 lambda 函数将计数存储在 faunadb 中,因此每次单击按钮时它都会递增。这是工作。
对于客户端,我正在使用 localStorage 更新组件 hitCounter 编号的状态,因此每次单击按钮时我都会更新 localStorage。
所有这些都很好用。但是,如果我通过单击 StoryBlock
中的关闭按钮更改 StoryPopFull
的状态(在下面的代码中看到)并通过单击更多按钮重新打开,状态将保持 localStorage 状态,这很好。但是,如果我更改 StoryPop
的状态,关闭 StoryGrid
重新打开所有内容, SvgAnimation
(命中计数器所在的组件)的状态正在从 graphQL 查询中获取它,现在就可以了如果查询速度足够快,但是在 lambda、faunadb 和点击页面刷新之间大约有 20 秒的延迟,因为我没有使用 graphql 订阅,所以必须有某种刷新。
什么是好的解决方案,以便在用户使用站点时使用本地存储来跟踪计数器,但是当他们 return 或刷新页面(不是组件重新加载)时,我可以更新本地存储graphql 查询。
这是我到目前为止的代码,提前致谢。
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 响应在获取后的任何内容。您可能需要调整它和代码中的其他内容,以确保它只在您需要时发生。为此,您可以考虑利用 useLazyQuery
和 useEffect
仅在您的组件首次安装时调用此查询。
像这样
const fetchHitCounter = useLazyQuery(HIT_COUNTER, {
onCompleted({ findHitCounterByID }) {
window.localStorage.setItem('count', findHitCounterByID.amount);
}
});
useEffect(() => {
fetchHitCounter();
}, []);