Home > Net >  Work with async functions in useEffect - how to get the [[promiseresult]] - not using .then()
Work with async functions in useEffect - how to get the [[promiseresult]] - not using .then()

Time:11-03

In my useEffect I try to get a user id token and when I have this token, I fetch data from my server with the token as authorization header. With the data I fill some highcharts options and render a chart.

The problem is that I'm not able to access the [[PromiseResult]], it returns the complete Promise.

I use firebase as a user database and wrap the user authentification in a context.

Edit: id I use .then() I would have to repeat a bunch of my code twice as my header constant depends on the outcome and the fetching of data depends on the header like so:

if(currentUser) {
      await currentUser.getIdToken(/* forceRefresh */ true).then(
        // ... defining the header with idToken
        // ... continue with the rest
      )
    } else {
        // ... defining the header as "unauthorized"
        // ... continue with the rest
    }

So what would be the solution for it?

Here is my complete component:

import React, {useState, useEffect } from "react";
import Highcharts from "highcharts/highstock";
import HighchartsReact from "highcharts-react-official";
import { useAuth } from "../../../contexts/AuthContext"

import ChartLoadingScreen from '../ChartLoadingScreen'


export default function MyChart(){
  const [isMounted, setMounted] = useState(false)
  const [options, setOptions] = useState(HighchartsTheme)
  const { currentUser } = useAuth();
  
  const HighchartsTheme = {
    title: {
        text: undefined,
    },
    series: [ ],
    accessibility: {
        enabled: false
    },
    yAxis: [{
        opposite: true,
        type: 'linear',
        labels: {
            align:'right',
        },
    },
    {
        opposite: false,
        type: 'logarithmic',
    }]
  };


  useEffect(() => {
    const getIdToken = async () => {
      const idToken = await currentUser.getIdToken(/* forceRefresh */ true);
      return(idToken);
    }

    setMounted(false);
    console.log(currentUser)
    const idToken = currentUser ? getIdToken() : "unauthorized";
    console.log(idToken)

    let headers = new Headers();
    headers.append('authorization', idToken);

    Promise.all([
      fetch("https://my-server-side/data1"),
      fetch("https://my-server-side/data2", { headers: headers })
    ]).then(responses =>
      Promise.all(responses.map(response => response.json()))
    ).then(data => {
      console.log(data);
      setSeriesData(data[1]);
      options.series = [{ data: data[0],  yAxis: 1}];
      options.series.push({ data: data[1], yAxis: 0})
      updateChart();
      setMounted(true);
    }
    ).catch(err =>
      console.log(err)
    );

    return () => {
      setMounted(false);
      setOptions({});
    };  
  }, [chartDataEndpoint]);

  const updateChart = () => {
    setOptions(prevState => ({ ...prevState}));
  };

  return (
    <>
      {isMounted ?
        <>
          <div>
            <HighchartsReact
              highcharts={Highcharts}
              constructorType={"stockChart"}
              options={options}
            />
          </div>
        </>
      :
        <ChartLoadingScreen isDefault={true}/>
      }
    </>

  );
}

CodePudding user response:

One problem with useEffect it's dismount function is in the form ->() => void, and not () => Promise<void>, as such if you just mark a useEffect as an async function it's going to return a Promise, and React is just expecting a function and not a promise.

A simple solution to this is to just wrap your code inside a asnyc IFFE..

eg.

useEffect(() => {
  (async () => { 
    //we can now use async/await.
    .....
    const idToken = currentUser ? await getIdToken() : "unauthorized"; 
    .....
  })();
  //our return is still a plain function
  return () => {
    //dismount stuff here
  }
},[chartDataEndpoint]);

CodePudding user response:

Your useEffect "callback" should be async:

  useEffect(async() => {
    let x = await fetch(URL);
    x = await x.json();
    setData(x);}, []);
  • Related