0

I am using react hook instead of class based component but it is not updating the state when i fetch data from graphql API.

Here you go for my code:

import React, { useEffect, useState } from 'react';
import client from '../gqlClient';
import { gql, ApolloClient, InMemoryCache  } from '@apollo/client';


const client = new ApolloClient({
  uri: 'http://localhost:8000/graphql/',
  cache: new InMemoryCache(),
});


function EmpTable() {

  const [employee, setEmployee] = useState({});

    useEffect(() => {

        client
            .query({
                query: gql`
                query {
                  employees {
                    name
                  }
                }
                `
            })
            .then(result => {
              setEmployee({result});
              console.log(employee);
            });
    }, [])

    return (
        <div>return something</div>
    )
};


export default EmpTable;

When i print the employee It prints the initial value only.

But when print result, the console showing all the data that i have from API.

I made the useEffect only run once the page/component is loaded but it is not working.

Can anyone help me how to fix the issue?

  • Does this answer your question? [React hooks setState not updating immediately](https://stackoverflow.com/questions/56510211/react-hooks-setstate-not-updating-immediately) – JBallin Dec 20 '20 at 07:18
  • Nope, It's not similar to this, thanks –  Dec 20 '20 at 07:23
  • @pythonerdude Do `console.log({result});` you just set employee with that anyway but you can't use employee because that is a [stale closure](https://dmitripavlutin.com/react-hooks-stale-closures/) – HMR Dec 20 '20 at 07:28

3 Answers3

2

setEmployee is the asynchronous method so you can't get the updated value of employee immediately after setEmployee.

setEmployee({result});
console.log(employee); // This will show the old `employee` value.

You should get the updated result in the useEffect with adding a employee dependency.

useEffect(() => {
        client
            .query({
                query: gql`
                query {
                  employees {
                    name
                  }
                }
                `
            })
            .then(result => {
              setEmployee({result});
              console.log(employee);
            });
}, [])

useEffect(() => {
  console.log(employee);
}, [employee]);
wangdev87
  • 8,611
  • 3
  • 8
  • 31
  • But the problem is, when i made useEffect dependent on employee, the API call is getting continually thousand million time, it's call the API infinitly and not stopping, just got my browser crushed –  Dec 20 '20 at 07:17
  • 1
    what i said is you need to add one more useEffect in your code – wangdev87 Dec 20 '20 at 07:24
  • 1
    if you add `employee` usage in render, it will be re-rendered as soon as employee value is updated by setEmployee. – wangdev87 Dec 20 '20 at 07:35
  • No, It's not doing –  Dec 20 '20 at 08:16
0

You need to use useEffect hook to achieve this.

more information about How to use setState callback on react hooks How to use `setState` callback on react hooks

here is your code should be:

import React, { useEffect, useState } from 'react';
import client from '../gqlClient';
import { gql, ApolloClient, InMemoryCache  } from '@apollo/client';


const client = new ApolloClient({
  uri: 'http://localhost:8000/graphql/',
  cache: new InMemoryCache(),
});


function EmpTable() {

  const [employee, setEmployee] = useState({});

    useEffect(() => {
        client
            .query({
                query: gql`
                query {
                  employees {
                    name
                  }
                }
                `
            })
            .then(result => {
              setEmployee({result});
              
            });
    }, [])

   useEffect(() => {
      console.log(employee);
   }, [employee]);

   return (
      <div>{JSON.stringify(employee,null,2)}</div>
   )
};


export default EmpTable;
Hamid Shoja
  • 3,838
  • 4
  • 30
  • 45
  • Do i need to use useEffect two times like that you mentioned? –  Dec 20 '20 at 07:22
  • 1
    yes because their dependencies are different. – Hamid Shoja Dec 20 '20 at 07:24
  • I see, but when i use two useEffect, it works, problem is, i cant render the data, when i try to return to render in html, the employee is empty, coz, the employee update later, what is the solutation for this? –  Dec 20 '20 at 07:30
  • 1
    I added return data in my response, but you should know *employee* is an async state and it will render the data when it’s ready. so you should use state in the parent component or send them as a prop to another component. Besides there is a component named that you can wait till loading it. – Hamid Shoja Dec 20 '20 at 07:38
  • 1
    @pythonerdude I added another solution for your last problem. – Hamid Shoja Dec 20 '20 at 07:44
0

There is another solution that you can use a custom hook to use your returned value in any component you want to use.

import React, { useEffect, useState } from 'react';
import client from '../gqlClient';
import { gql, ApolloClient, InMemoryCache  } from '@apollo/client';


const client = new ApolloClient({
  uri: 'http://localhost:8000/graphql/',
  cache: new InMemoryCache(),
});

const useCustomApi=()=>{
    const [employee, setEmployee] = useState({});
    useEffect(() => {
        client
            .query({
                query: gql`
                query {
                  employees {
                    name
                  }
                }
                `
            })
            .then(result => {
              setEmployee({result});
              
            });
    }, [])


return employee;
}

function EmpTable() {

    const employee = useCustomApi();
    console.log(employee);

   return (
      <div>{JSON.stringify(employee,null,2)}</div>
   )
};


export default EmpTable;
Hamid Shoja
  • 3,838
  • 4
  • 30
  • 45
  • you already updated your first answer, you don't need to post another duplicated answer. – wangdev87 Dec 20 '20 at 08:00
  • @WilliamWang tnx for you attention, I answered in two different way, because there were 2 problems, at first the questioner wanted to log the state and he had problem to work with useEffect, second he wanted to return the state so I thought there are different – Hamid Shoja Dec 20 '20 at 08:23