0

I took a two day React training class last week. The instructor tried to jam a weeks worth of info into two days. We slapped together a crude blackjack game in the "class" (or is that Class<T>: => () await (...p) ha ha little Typescript joke there.) The class did not get around to covering how to access a REST API. So here I am stuck with a bunch of confusing unreadable code that I am not even sure is React or Typescript. Any whooo this is my App.tsx file:

import React, {useState} from 'react';
import './App.css';
import {fetchUser, User, UserCtx} from "./User";
import {useAsync} from "./ss-react-utils";

const AppLoaded = ({user}: {user: User}) => {
  return <div className="App">
    {user.userName}
  </div>;
};

const AppLoading = () => {
  return <div>Loading ...</div>;
};

const App: React.FC = () => {  // I guess the FC stands for F*king Confusing 
  const [user, setUser] = useState<User | null>(null);

  useAsync({
    op: fetchUser,
    onSuccess: setUser,
    deps: []
  });

  if (user !== null) {
    return <AppLoaded user={user} />;
  } else {
    return <AppLoading/>;
  }
}

export default App;

Here's the ss-react-utils.tsx file:

import React, {CSSProperties, DependencyList, useEffect} from "react";

export type Op<T> = () => Promise<T>;
export type OnSuccess<T> = (data: T) => void;

export function useAsync<T>({op, onSuccess, deps}: { op: Op<T>, onSuccess: OnSuccess<T>, deps?: DependencyList }) {

    useEffect(() => {
        const doOp = async () => {
            const data: T = await op();
            onSuccess(data);
        };
        doOp();

        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, deps);
}

... some other unrelated ( I think ) code ...

when I run that code I get this ... enter image description here

I would like to know how to handle the error and display the login page to the user if the REST API returns a 403 forbidden error.

And Yes I know the REST API is returning a 403 error. So please don't answer the question with you are getting a 403 error. :)

Also I have seen a lot of answers that say use componentDidMount but the instructor said that was the old way of doing React and he was going to teach about hooks instead. Well would like to try what the instructor was getting at before I completely give up on the "New" way to code React. And probably React all together. So please help :)

UPDATE: I am using Django Rest Framework and it is behaving as expected. enter image description here

2
  • Note that if the server responds with 404 and valid json the fetch result will not throw so you have to check the response.json if you got data or a serer error. When it's a server error you can Promise.reject that error and in the catch set error. You currently are not setting a loading state before the async and do not check if the component is still mounted when the promise resolves and you set state you cannot set state on unmounted component so you should check if it's still mounted after an async process finishes and before setting state. Commented Nov 19, 2019 at 7:59
  • I think this might be what I need to see: medium.com/better-programming/… Commented Nov 23, 2019 at 20:21

3 Answers 3

1
const App: React.FC<{id}> = ({id}) => {
  const op = useCallback(()=> fetchUser(id), [id]);
  const { data: user, loading, error } = useFetch(op);
  useEffect(()=> {
     if (!error){return}
     alert(error); // if wanna alert error;
  }, [error]);
  return (
    <>
      {loading && <AppLoading />}
      {user && <AppLoaded user={user}/>}
      {error && <pre>{error.message | error}</pre>}
    </>
  )
}
function useFetch<T>(op: ()=> Promise<T>){
  const [loading, setLoading] = useState(false);
  const [data, setData] = useState<T | null | undefined>();
  const [error, setError] = useState<string | null>(null);
  const id = useRef(0);
  useEffect(()=> ()=> {
    // on unmount
    id.current = 0;
  }, []);
  useEffect(()=> {
     const currentID = ++id.current;
     setLoading(true);
     op().then((data)=> {
       // ignore when query changed
       if (id.current !== currentID) { return; }
       setData(data);
       setLoading(false);
       setError(null);
     }, (err)=> {
       if (id.current !== currentID) { return; }
       setError(err.message || err);
       setLoading(false);
     })
  }, op);
  return {data, loading, error}
}
Sign up to request clarification or add additional context in comments.

Comments

0

In my last project, I have a problem with async download data from api. Then I must use something like this:

componentDidMount() {
fetch("API")
  .then(res => res.json())
  .then(json => {
    ...
    this.setState({ data });
  });
}

But this code is for the class component. Can you test this same code with only fetch data?

We will exclude in this way whether it is the fault of the data download itself.

Comments

0

You can handle error in this way. Here is the example:-

componentDidMount() {
    fetch(URL)
      .then(results => results.json())
      .then(data => this.setState({ results: data }))
      .catch(error=>{   //here you can handel errors
          if(error.response){
              alert("Error occurred"); 
          }
      });
  }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.