Бесконечный l oop в вызове React GET API и правильный способ использования хуков и useState () - PullRequest
0 голосов
/ 06 августа 2020

Я новичок в React, и я разрабатываю приложение со стандартными операциями CRUD для удаленного сервера Express. js и MongoDB.

На странице мне нужно отобразить значения из Вызов GET API на удаленный сервер, сделанный с помощью Ax ios. Каждый объект в виде нескольких полей, а также поле company (значение в столбце Exhibitor , например, выглядит как 5f280eb605c9b25cfeee285 c ) соответствует значению поля объекта _id Mon go другого объекта в другой коллекции.

Мне нужно восстановить в таблице исходное значение, сделать другое Вызов API и получение поля name (например, Пример строки названия компании ) от объекта с этим _id. После этого мне нужно отобразить его в полях таблицы вместо _id.

Чтобы было понятнее, например, поле item.company 5f27e8ee4653de50faeb1784 будет отображаться как Название компании пример строки .

Также мне нужно сделать то же самое со столбцом Status (но без вызова GET API на удаленный сервер), где мне нужно отобразить значок в зависимости от item.active значение, которое является логическим.

Это нужно делать без какой-либо кнопки, но когда я открываю страницу автоматически.

Я сделал стандартный javascript, но я получаю бесконечное l oop, я полагаю, потому что React вызывает функцию каждый раз при рендеринге.

Как правильно выполнить эту операцию?

Вот ошибки из консоли после l oop

xhr. js: 178 GET http://myserver.com/companies/5f280eb605c9b25cfeee285c net :: ERR_INSUFFICIENT_RESOURCES

import React, { useState, useEffect, useCallback } from 'react'
import { Tab, Tabs, Col, Form, Button } from 'react-bootstrap'
import { FiTrash, FiCloud, FiPhoneCall, FiUserCheck, FiUserX, FiEye } from 'react-icons/fi'
import axios from 'axios'

const EventProfile = (props) => {

  // SOME CODE HERE //

  //GET STANDS FROM DB

  const [allStands, viewStands] = useState([{}]);

  useEffect(() => {
      const id = props.match.params.id
      const fetchStands = async () => {
      const response = await axios.get(`http://myserver.com/stands/${id}`);
      viewStands(response.data);
    }
    fetchStands();
  }, [])


    // RECOVER NAME USING THE COMPANY ID FROM ANOTHER COLLECTION

    const [companyNameGetted, getCompanyName] = useState({})

  const getCompanyFromId = useCallback((props) => {
    const id = props;
    const getCompany = async () => {
      const response = await axios.get(`http://myserver.com/companies/${id}`);
      getCompanyName(response.data);
    }
    getCompany([]);
  }, [])

    // DISPLAY ICON DEPENDING ON OBJECT active FIELD


      const handleStandStatus = (status) => {
    if(status === true) {
      return <FiCloud style={{color: "green"}}/>;
    } else {
      return <FiCloud style={{color: "grey"}} description="Offline"/>;
    }
  }
   

   // OTHER CODE HERE //
return (

     //SOME CODE HERE//
    
             <Tab eventKey="stands" title="Stands">
          <div className="py-12 w-full">
            <table className="table table-lg">
              <thead>
                <tr>
                  <th>Status</th>
                  <th>Name</th>
                  <th>Exhibitor</th>
                  <th>Size</th>
                  <th>Color Palette</th>
                </tr>
              </thead>
              <tbody>
                {allStands.map((item, index) =>{
                  return(
                    <tr key={index}>
                      <td>{handleStandStatus(item.active)}</td>
                      <td><Link to={`/standProfile/${item._id}`}>{item.name}</Link></td>
                      <td>{getCompanyFromId(item.company)}<Link to={`/companyProfile/${item.company}`}><span>{companyNameGetted.name}</span></Link></td>
                      <td>{item.size}</td>
                      <td>{item.colorPalette}</td>
                    </tr>
                  )
                  })}
              </tbody>
            </table>
          </div>
        </Tab>


     // OTHER CODE HERE //

 )
}

export default EventProfile

1 Ответ

1 голос
/ 06 августа 2020

Вероятно, эта часть отвечает за бесконечное l oop:

<td>{getCompanyFromId(item.company)}<Link to={`/companyProfile/${item.company}`}><span>{companyNameGetted.name}</span></Link></td>

, потому что вы вызываете функцию в возврате вашего компонента, которая затем функция вызовет функцию getCompany, которая будет обновите состояние companyNameGetted.

Состояние companyNameGetted указывается при возврате компонента, поэтому вызов getCompanyFromId приведет к повторному рендерингу, который получит компанию, изменит состояние, повторно -render, et c, что приводит к бесконечному l oop.

Вы можете получить компании в рамках useEffect после того, как получите все стойки, или вы можете установить

useEffect(() => {get all company from allStands}, [allStands]);

, чтобы он отражал allStands изменения состояния.

Изменить: вот пример, чтобы подробнее описать, что я имею в виду.

const EventProfile = props => {
  // usually you'll want to name the variables as so:
  // a noun/object for the first one (stands)
  // a setter for the second one, since it is a function to set the `stands`
  const [stands, setStands] = useState([]);
  const [companies, setCompanies] = useState({});

  // usual useEffect that'll be triggered on component load, only one time
  useEffect(() => {
    const fetchStands = async () => {
      const response = await axios.get("stands url here");
      setStands(response.data);
    };
    fetchStands();
  }, []);

  //another useEffect that'll be triggered when there's a change in the dependency array given, i.e. the `stands` variable. so, it'll fetch company names whenever the `stands` state changes.
  useEffect(() => {
    const fetchCompanies = async () => {
      const newCompanies = {...companies};
      // wait for all company names have been retrieved
      await Promise.all(stands.forEach(s => {
        const id = s.company;
        const response = await axios.get("company url here with " + id);
        newCompanies[id] = response.data;
      }));
      setCompanies(newCompanies);
    };
    fetchCompanies();
  }, [stands]);

  return (
    // ... some components
    {stands.map((item, index) => (
      <tr key={index}>
        <td><Link to={`/some/url/${item.company}`}>{companies[item.company]}</Link></td>
      </tr>
    )}
  );
}
...