Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

205
Vistas
calling useQuery conditionally returns wrong output only for the first time

Please help me understand why am I getting no items on first request. I have this component ExportData that calls Context only when prompted, dialogConfirmation is linked to a button, snippet:

ExportData:

import useItem from '../../context/ItemsContext'

const ExportData = () => {
  const { items, getAll } = useItem()

  const dialogConfirmation = confirm => {
    if (confirm) {
      getAll()
    }
  }
}

ItemsContext:

import React, {
  useState,
  useReducer,
  createContext,
  useContext,
  useEffect,
} from 'react'
import { useQuery } from '@apollo/client'
import { CURRENT_MONTH, ALL_ITEMS } from '../graphql/queries'
import itemReducer from '../reducers/itemReducer'

export const ItemProvider = ({ children }) => {
  let items = []
  const [all, setAll] = useState(false)

  const selectedMonth = dayjs(new Date()).format('YYYY-MM')
  const [state, dispatch] = useReducer(itemReducer, [])

  const result = useQuery(all ? ALL_ITEMS : CURRENT_MONTH, {
    variables: all ?  null : { selectedMonth },
  })

  if (result.data && result.data.getCurrentMonth) {
    items = [...result.data.getCurrentMonth]
  }

  if (result.data && result.data.getItems) {
    items = [...result.data.getItems]
  }

  useEffect(() => {
    if (result.data && result.data.getCurrentMonth) {
      dispatch({
        type: 'ALL',
        items: result.data.getCurrentMonth,
      })
    }
    if (result.data && result.data.getItems) {
      dispatch({
        type: 'ALL',
        items: result.data.getItems,
      })
    }
  }, [result.data])

  const getAll = () => {
    setAll(true)
  }

  const value = {
    items: state.items,
    getAll,
  }
  return <ItemContext.Provider value={value}>{children}</ItemContext.Provider>
}

Reducer:

const itemReducer = (state, action) => {
  switch (action.type) {
    case 'ALL':
      return {
        ...state,
        items: action.items,
      }
    default:
      return state
  }
}

Query CURRENT_MONTH returns only items from current month - that should be the default one.

Query ALL_ITEMS returns all items in database.

What happens currently, when I use the getAll function in ExportData, on the first try, it returns only the items from current month, however on the second try, it returns correct output(all data).

When debugging itemReducer, all items are in the action.items however the output within the component gets only the old data...On the second try however, it works fine.

What am I doing wrong here?

about 4 years ago · Juan Pablo Isaza
1 Respuestas
Responde la pregunta

0

What is happening here:

  1. Component is initially rendered (no data yet)
  2. useEffects are fired: (inside component) does nothing, (inside useQuery) fires request to gql api
  3. after some time when request is fulfilled state inside useQuery is set with data
  4. Becouse of that component gets rerender (data is present but not yet used in state.items becouse dispatch was not fired yet)
  5. useEffects are fired and this time dispatch is called.
  6. Component rerenders again because dispatch changed useReducer state and this time state has items inside

In this process react renders 3 times. If you place console.log(state.items) inside component it will look like this:

[]             // no data yet
[]             // data is present but not yet used by `state`
[<your data>]  // data is present and used by state

You can solve that by removing useEffect and useReducer:

  1. Component is initially rendered (no data yet)
  2. useEffects are fired: (inside component) does nothing, (inside useQuery) fires request to gql api
  3. after some time when request is fulfilled state inside useQuery is set with data
  4. Becouse of that component gets rerender (data is passed directly to value)

In this process react renders 2 times. If you place console.log(items) inside component it will look like this:

[]            // no data yet
[<your data>] // data is present and used
import React, {
  useState,
  createContext,
  useContext,
} from 'react'
import { useQuery } from '@apollo/client'
import { CURRENT_MONTH, ALL_ITEMS } from '../graphql/queries'

export const ItemProvider = ({ children }) => {
  const [all, setAll] = useState(false)

  const selectedMonth = dayjs(new Date()).format('YYYY-MM')

  const result = useQuery(all ? ALL_ITEMS : CURRENT_MONTH, {
    variables: all ?  null : { selectedMonth },
  })

  const getAll = () => {
    setAll(true)
  }

  const items = result?.data.getCurrentMonth || result?.data.getItems || []

  const value = {
    items,
    getAll,
  }
  return <ItemContext.Provider value={value}>{children}</ItemContext.Provider>
}
about 4 years ago · Juan Pablo Isaza Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda