Home > OS >  Delay in loading the array crushs the app
Delay in loading the array crushs the app

Time:03-20

Yo-yo everyone,

along my path of practicing the art of React, I noticed a bug that I couldn't seem to find a good source to help me understand what causes the problem.

My array in a child component takes too long to load, resulting in an error.

  1. The data is fetched from "jsonplaceholder," users list.
  2. Data is set as a state.
  3. Sent to "UserProfilePage".
  4. Sent to "UserProfileComponent".

Trying to reach the URL "/user/1" will not succeed since the object is undefined.

*) Commenting the "UserProfileComponent," and then uncomment without refreshing will successfully load the page.
*) Coping (not fetching) the data to the App.js, assigning it to the state, will not crush the system.

APP.js

import { Component } from "react";
import { Redirect, Route, Switch } from "react-router-dom";
import "./App.css";

import Navigation from "./components/header/Navigation";
import PostsLog from "./components/Posts/PostsLog";

import UserProfileCollection from "./pages/UserProfileCollection";
import UserProfilePage from "./pages/UserProfilePage";

const POST_ENDPOINT = "https://jsonplaceholder.typicode.com/posts";
const USER_ENDPOINT = "https://jsonplaceholder.typicode.com/users";

class App extends Component {
  constructor() {
    super();
    this.state = {
      exUsersArray: [],
      exPostsArray: [],
    };
  }

  async componentDidMount() {
    try {
      const responseUser = await fetch(USER_ENDPOINT);
      const responsePost = await fetch(POST_ENDPOINT);
      const dataResponseUser = await responseUser.json();
      const dataResponsePost = await responsePost.json();
      this.setState({ exUsersArray: dataResponseUser });
      this.setState({ exPostsArray: dataResponsePost });
    } catch (error) {
      console.log(error);
    }
  }
  render() {
    const { exUsersArray, exPostsArray } = this.state;
    console.log(exUsersArray);
    return (
      <div className="app">
        <Navigation />
        <main>
          <Switch>
            {/* REROUTES */}
            <Route path="/" exact>
              <Redirect to="/feed" />
            </Route>
            <Route path="/users" exact>
              <Redirect to="/user" />
            </Route>

            {/* REAL ROUTES */}
            <Route path="/feed">
              <PostsLog usersInfo={exUsersArray} usersPosts={exPostsArray} />
            </Route>
            <Route path="/user" exact>
              <UserProfileCollection usersInfo={exUsersArray} />
            </Route>

            {/* DYNAMIC ROUTES */}
            <Route path="/user/:userId">
              <UserProfilePage usersInfo={exUsersArray} />
            </Route>
          </Switch>
        </main>
      </div>
    );
  }
}

export default App;

UserProfilePage.js

import { useParams } from "react-router-dom"
import UserProfileComponent from "../components/UserProfileComponent";

const UserProfilePage = ({usersInfo}) => {
    const params = useParams();
    const foundUser = usersInfo.find((user) => Number(user.id) === Number(params.userId))
    console.log("found user  ", foundUser);
    // console.log(usersInfo);
    console.log(params, " is params");
    
    return(
        <div>
            <UserProfileComponent userProfile={foundUser}/>
            <p>Yo YO</p>
        </div>
    )
}

export default UserProfilePage;

UserProfileComponent

const UserProfileComponent = ({userProfile}) => {
console.log(userProfile)

  return (
    <div className="text-group">
        <div className="wrap-post">
        <p>
          <strong>Info</strong>
        </p>
        <img
          src={`https://robohash.org/${userProfile.Id}.png`}
          id="small-profile"
          alt="user profile in circle"
        />
        <p><u><strong>ID</strong></u> : {userProfile.id}</p>
        <p>Name: {userProfile.name}</p>
        <p>@{userProfile.username}</p>
        <p>Email: {userProfile.email}</p>
        <p>
          {userProfile.address.street} {userProfile.address.suite}<br/>
          {userProfile.address.zipcode} {userProfile.address.city}
        </p>
        <p>Global position</p>
        <p>{userProfile.address.geo.lat}, {userProfile.address.geo.lang}</p>
        <p>{userProfile.phone}</p>
        <p>{userProfile.website}</p>
        <p>Company</p>
        <p>{userProfile.company.name}</p>
        <p>{userProfile.company.catchPhrase}</p>
        <p>{userProfile.company.bs}</p>
      </div>
    </div>
  );
};

export default UserProfileComponent;

Complete repository here.
I will be happy to any tips to help me understand what happened here.
Appreciation will be given to any tip that will help me be a better programmer.

Best wishes y'all.

CodePudding user response:

it seems like usersInfo hasn't loaded a quick way to fix it is to just add this to the users component.

UserProfilePage.js


import { useParams } from "react-router-dom"
import UserProfileComponent from "../components/UserProfileComponent";

const UserProfilePage = ({usersInfo}) => {
    const params = useParams();
    if(!usersInfo) {
        return <p>Loading...</p>
    }
    const foundUser = usersInfo.find((user) => Number(user.id) === Number(params.userId))
    console.log("found user  ", foundUser);
    // console.log(usersInfo);
    console.log(params, " is params");
    
    return(
        <div>
            <UserProfileComponent userProfile={foundUser}/>
            <p>Yo YO</p>
        </div>
    )
}

export default UserProfilePage;


UserProfileComponent.js

const UserProfileComponent = ({userProfile}) => {
  if(!userProfile) {
    return <p>Loading...</p>
  }


  console.log(userProfile)

  return (
    <div className="text-group">
        <div className="wrap-post">
        <p>

CodePudding user response:

I see that you're rendering your compoonent without doing any null check in UserProfileComponent. Actually to be a better programmer or doing better work, you have to control every null case in order not to crash your app.

<p><u><strong>ID</strong></u> : {userProfile.id}</p>
        <p>Name: {userProfile.name}</p>
        <p>@{userProfile.username}</p>
        <p>Email: {userProfile.email}</p>
        <p>
          {userProfile.address.street} {userProfile.address.suite}<br/>
          {userProfile.address.zipcode} {userProfile.address.city}
        </p>
        <p>Global position</p>
        <p>{userProfile.address.geo.lat}, {userProfile.address.geo.lang}</p>
        <p>{userProfile.phone}</p>
        <p>{userProfile.website}</p>
        <p>Company</p>
        <p>{userProfile.company.name}</p>
        <p>{userProfile.company.catchPhrase}</p>
        <p>{userProfile.company.bs}</p>

You'll see that there's no null check. It would be better if you have some null check on your userProfile

Also, my suggestion is, you can create a loading in your state.

  1. Before sending your request, you can set the loading to true.

  2. And when your loading is true, you can show some spinner or sth like that. When your request finishes, you can set the loading variable to false and you can show your data.

The main point is, always use a loading variable to check the loading state instead of checking the null | undefined state of your data.

  • Related