Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

199
Views
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 answers
Answer question

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 Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!