How to call a react hook fetch request in a functional component to access data then pass to a class component to map?

LauraAnnabel89 :

After a huge amount of trial and error for a complex webGL project I have landed on a solution that will reduce the amount of re-engineering working, threejs code (from another developer) and, as this project is extremely time restrained, reduce the amount of time needed. It's also worth noting my experience of this is limited and I am the only developer left on the team.

The project current accepts a large array of random user data, which is exported from a js file and then consumed here...

import Users from "./data/data-users";

class UsersManager {
  constructor() {
    this.mapUserCountries = {};
  }

  init() {
    Users.forEach(user => {
      const c = user.country;

      if (!this.mapUserCountries[c])
        this.mapUserCountries[c] = { nbUsers: 0, users: [] };
      this.mapUserCountries[c].nbUsers++;
      this.mapUserCountries[c].users.push(user);
    });
  }

  getUsersPerCountry(country) {
    return this.mapUserCountries[country];
  }
}

export default new UsersManager();

Here is my fetch request..

import { useState, useEffect } from "react";

const FetchUsers = () => {
  const [hasError, setErrors] = useState(false);
  const [users, setUsers] = useState({});

  async function fetchData() {
    const res = await fetch(
      "https://swapi.co/api/planets/4/"
    );
    res
      .json()
      .then(res => setUsers(res))
      .catch(err => setErrors(err));
  }

  useEffect(() => {
    fetchData();
  }, []);

  return JSON.stringify(users);
};

export default FetchUsers;

I have run into lots of issues as the UserManager is a class component and if I import my fetchUsers into this file, call it and save it to a variable like so const Users = fetchUsers(); it violates hooks.

I want to be able to return a function that will return my users from the database as an array.

That will then be able to be passed into the UserManager in the same way the hard coded data is and mapped over to be actioned by LOTS of other files.

I've mocked up a small codesandbox with what the flow would be ideally but I know I need a solution outside of hooks...

https://codesandbox.io/s/funny-borg-u2yl6

thanks

--- EDIT ---

import usersP from "./data/data-users";

class UsersManager {
  constructor() {
    this.mapUserCountries = {};
    this.state = {
      users: undefined
    };
  }

  init() {
    usersP.then(users => {
      this.setState({ users });
    });
    console.log(usersP);
    this.state.users.forEach(user => {
      const c = user.country;
      if (!this.mapUserCountries[c])
        this.mapUserCountries[c] = { nbUsers: 0, users: [] };
      this.mapUserCountries[c].nbUsers++;
      this.mapUserCountries[c].users.push(user);
    });
  }

  getUsersPerCountry(country) {
    return this.mapUserCountries[country];
  }
}

export default new UsersManager();
console.log (UsersManager.js:16 Uncaught TypeError: Cannot read property 'forEach' of undefined
    at UsersManager.init (UsersManager.js:16)
    at Loader.SceneApp.onLoadingComplete [as callback] (App.js:39)
    at Loader.onAssetLoaded (index.js:20)
    at index.js:36
    at three.module.js:36226
    at HTMLImageElement.onImageLoad)
Olivier Boissé :

I fixed your sandbox example.

You cannot load the users synchronously (using import) as you need to make a http call to fetch the users so it's asynchronous.

As a result you can fetch the users inside the componentDidMount lifecycle method and use a state variable to store them once they are fetched

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=174710&siteId=1