В ответной проверке, обновилась ли страница, отключите localalstorage из запроса graphql, в противном случае сохраните текущее локальное хранилище для состояния - PullRequest
0 голосов
/ 30 апреля 2020

Я пытаюсь создать счетчик посещений, основанный на клике пользователя. Он увеличивает счетчик каждый раз, когда пользователь щелкает. Я бегу Гэтсби JS с реакции.

Я использую лямбда-функцию для сохранения счета в faunadb, поэтому он увеличивается с каждым нажатием кнопки. Это работает.

Для клиентской части я обновляю состояние номера HitCounter компонента с помощью localStorage, поэтому каждый раз, когда нажимается кнопка, я обновляю localStorage.

Все это работает довольно хорошо. Однако, если я изменю состояние StoryPopFull (см. Код ниже), нажав кнопку закрытия в StoryBlock, и открою снова, нажав кнопку more, состояние сохранит состояние localStorage, что является хорошим. Однако, если я изменю состояние StoryPop, закрывая StoryGrid, снова открою все, что состояние SvgAnimation (компонент, в котором живет счетчик посещений) берет его из запроса graphQL, теперь это было бы хорошо, если запрос пришел достаточно быстро , но между лямбда, faunadb и нажатием refre sh на странице задержка составляет около 20 секунд, потому что я не использую подписки graphql, поэтому должен быть refre sh вида.

Какое хорошее решение, когда пользователь использует localstorage сайта, чтобы отслеживать счетчик, но когда они возвращают или обновляют sh страницу (не перезагрузка компонента), я могу обновить localstorage с помощью запроса 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

Ответы [ 2 ]

1 голос
/ 03 мая 2020

Вы пытались установить функцию после завершения запроса?

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();
}, []);
1 голос
/ 03 мая 2020

Я думаю, что единственная проблема, с которой вы столкнулись сейчас, - это обнаружение погоды или обновление страницы. Поэтому, если вы смогли обнаружить refre sh, вы могли бы выполнить соответствующее действие по refre sh, для этого я рекомендую вам взглянуть на этот вопрос:

Определение Refre sh

Так что, как только вы сможете обнаружить refre sh, вы можете добавить индекс в своем хранилище, который может указывать на это, и предпринимать необходимые действия.

...