Home > Enterprise >  Render Value Only After Error Handling and Fetch is complete
Render Value Only After Error Handling and Fetch is complete

Time:06-07

I am new to React JS and still struggling in mastering a few concepts.

I am trying to do error handling for my code and only display the API response only after the Fetch is complete.

Below I have my code which is what I have done.

import React, { useState, useEffect } from "react";

function Transaction({ response }) {
  const [transaction, setTransaction] = useState([]);
  const token = "2c506c6b-d880-36bb-bdba-a035d1464b35";

  const requestOptions = {
    method: "GET",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${token}`
    },
  };

  useEffect(() => {
    fetch(
      "https://api.flash-internal.flash-group.com/ecommerceManagement/1.0.0/api/transaction/5KISDW53",
      requestOptions
    )
      .then((response) => response.json())
      .then((data) => setTransaction(data));
  }, []);

//   console.log(transaction.result.details[0].vouchers[0].result);

  return (
    <>
        <div>
            Hello
            <b>Transaction Status:</b> {transaction.status} <br />
        </div>
    </>
  );
}

export default Transaction;

And below is how I am trying to do some clean error handling. Can someone help me, or at least refer me to where I can learn how to do this properly.

import React, { useState, useEffect } from "react";

function Transaction({ response }) {
  const [transaction, setTransaction] = useState([]);
  const token = "2c506c6b-d880-36bb-bdba-a035d1464b35";

  const requestOptions = {
    method: "GET",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${token}`,
    },
  };

  function handleErrors(response) {
    if (!response.ok) {
      throw Error(response.statusText);
    }
    return response;
  }

  useEffect(() => {
    fetch(
      "https://api.flash-internal.flash-group.com/ecommerceManagement/1.0.0/api/transaction/5KISDW53",
      requestOptions
    )
      .then(handleErrors)
      .then((response) => console.log("ok"))
      .catch((error) => console.log(error))
      .then((response) => response.json())
      .then((data) => setTransaction(data));
  }, []);

  //   console.log(transaction.result.details[0].vouchers[0].result);

  return (
    <>
      <div>
        <b>Transaction Status:</b> {transaction.status} <br />
      </div>
    </>
  );
}

export default Transaction;

CodePudding user response:

An issue I see is that you are implicitly returning the void result of a console log in the Promise chain, so later thenables aren't receiving the unpacked JSON response value.

useEffect(() => {
  fetch(
    "......",
    requestOptions
  )
    .then(handleErrors)
    .then((response) => console.log("ok")) // <-- returns undefined!
    .catch((error) => console.log(error))
    .then((response) => response.json()) // <-- can't call `json()` of undefined!
    .then((data) => setTransaction(data));
}, []);

It seems like you are asking about the fetch processing. I would suggest checking for the ok response before returning the json, right there inline. If you want to conditionally wait to display any fetched content then use a loading state.

Example:

function Transaction({ response }) {
  const [loading, setLoading] = useState(true);
  const [transaction, setTransaction] = useState();

  const requestOptions = {
    method: "GET",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${token}`,
    },
  };

  useEffect(() => {
    setLoading(true);
    fetch(
      ".....",
      requestOptions
    )
      .then((response) => {
        if (!response.ok) {
          throw Error(response.statusText);
        }
        return response.json();
      })
      .then((data) => {
        setTransaction(data)
      })
      .catch((error) => {
        console.log(error)
      })
      .finally(() => {
        setLoading(false);
      });
  }, []);

  if (loading) {
    return null; // or loading spinner/etc
  }

  return (
    <>
      {transaction
        ? (
          <div>
            <b>Transaction Status:</b> {transaction.status} <br />
          </div>
        )
        : <div>No transaction data</div>
      }
    </>
  );
}

If you want to display any errors then add some error state and some conditional rendering logic to display it, similar to the transaction state.

CodePudding user response:

You need to keep multiple states here.

  1. data: For the data from API
  2. isLoading: For Loading State
  3. isError: For Error State

State:

const [transactions, setTransactions] = useState({
  data: [],
  isLoading: false,
  isError: false,
});

and in your useEffect you should do

useEffect(() => {
  setTransactions({ ...transactions, isLoading: true });

  fetch(
    "https://api.flash-internal.flash-group.com/ecommerceManagement/1.0.0/api/transaction/5KISDW53",
    requestOptions
  )
    .then(handleErrors)
    .then((response) => console.log("ok"))
    .catch((error) => {
      setTransactions({ ...transactions, isError: true });
    })
    .then((response) => {
      setTransactions({
        ...transactions,
        data: response.json(),
        isLoading: false,
      });
    })
    .then((data) => setTransaction(data));
}, []);

Then you can have conditional rendering and show the loading bar and the data elements when it's ready

CodePudding user response:

you can use conditional rendering in react.

return (
    {
      transaction.length === 0 ? <></> :
        <>
          <div>
            <b>Transaction Status:</b> {transaction.status} <br />
          </div>
        </>

    }
)

you can use loading or anything that you want instead of <></> and also any other proper condition for data existence.

  • Related