Моя функция карты не возвращает никакой информации?

Я создаю простое приложение для реагирования на расходы. В этом приложении пользователи вводят описание, сумму и дату для определенной статьи расходов. Эта статья расходов или состояние «Бюджет» сохраняется в бэкенде. Теперь всякий раз, когда пользователь загружает страницу, делается запрос GET для получения «Бюджета» и выводится в таблицу.

Проблема в том, что API возвращает информацию, но функция карты ничего не выводит в таблицу.

Вот как данные выглядят в mongoDB:

_id:[some id] 
desc:"Lodging"
amount:30
date:"2020-05-02T03:28:49.000Z"

_id:[some id]
desc:"Shopping"
amount:120
date:"2020-05-02T03:55:41.000Z"

Вот что возвращает API, когда я записываю его в консоль:

{
  "success": true,
  "budget": [
    {
      "_id": "someId",
      "desc": "Lodging",
      "amount": 30,
      "date": "2020-05-02T03:28:49.000Z",
      "createdAt": "2020-05-18T03:29:01.879Z",
      "updatedAt": "2020-05-18T03:29:01.879Z",
      "__v": 0
    },
    {
      "_id": "someId",
      "desc": "Shopping",
      "amount": 120,
      "date": "2020-05-02T03:55:41.000Z",
      "createdAt": "2020-05-22T03:56:08.670Z",
      "updatedAt": "2020-05-22T03:56:08.670Z",
      "__v": 0
    }
  ]
}

Вот полный код:

 const [Budget, setBudget] = useState([]);

  const [loadingBudget, setloadingBudget] = useState(true);

  useEffect(() => {
    axios
      .get("[API Route]")
      .then((response) => {
        if (response.data.success) {
          console.log(response.data);
          setBudget([...Budget, response.data.budget]);
        } else {
          alert("Failed to get Budget");
        }
      });
    setloadingBudget(false);
  }, []);

 const values = Budget.map((i) => {
    return (
      <tr>
        <td>{i.desc}</td>
        <td>{i.amount}</td>
      </tr>
    );
  });

return (
    <React.Fragment>
      <table
        style={{ width: "40%", marginTop: "-300px", marginLeft: "720px" }}
        className="highlight">
        <thead className="thead-light">
          <tr>
            <th>Description</th>
            <th>Amount</th>
          </tr>
        </thead>
        <tbody>{!loadingBudget && values}</tbody>
      </table>
    </React.Fragment>

Я полагал, что компонент может отобразиться до того, как API вернет результат. В результате я добавил состояние loadingBudget, чтобы исправить это. Однако функция карты (то есть значения) ничего не возвращает. Любая обратная связь будет принята с благодарностью!


person traveler316    schedule 22.05.2020    source источник
comment
Ваш ответ API выглядит как массив массивов, внешний массив состоит из двух элементов, а первый элемент представляет собой массив из двух элементов. Было бы полезно, если бы вы могли использовать console.log(JSON.stringify(response.data, null, 2)), чтобы мы могли видеть реальную структуру, отправленную обратно...   -  person Heretic Monkey    schedule 22.05.2020
comment
@HereticMonkey Спасибо за предложение. Я обновил, как выглядит ответ.   -  person traveler316    schedule 22.05.2020


Ответы (1)


Когда вы получаете данные из API, убедитесь, что вы распространили их в массив. Итак, следующая строка:

setBudget([...Budget, response.data.budget]);

становится

setBudget([...Budget, ...response.data.budget]);

Затем переместите код Budget.map(...) в область <tbody>{!loadingBudget && values}</tbody> вместо того, чтобы назначать его values, чтобы он выглядел так:

<tbody>{!loadingBudget && Budget.map((i) => (
  <tr>
    <td>{i.desc}</td>
    <td>{i.amount}</td>
  </tr>
))}</tbody>

Я думаю, что происходит то, что values получает значение map, когда Budget изначально является пустым массивом... то есть ничем.

Если поставить в скобки Budget, React увидит, что это Observable, ну и понаблюдает за ним :). Затем, когда он изменится, чтобы иметь данные, он будет отображаться соответствующим образом.

person Heretic Monkey    schedule 22.05.2020
comment
Я действительно понял это. Как вы упоминали ранее, это вложенный массив. Итак, мне пришлось сделать вторую функцию карты. Это сработало: {!loadingBudget && Budget.map(function (subarray) { return subarray.map(function (val) { return ( <tr> <td>{val.desc}</td> <td>{val.amount}</td> </tr> ); }); })} Мне любопытно, почему бюджет стал вложенным массивом? - person traveler316; 22.05.2020
comment
вам следует попытаться записать в console.log ваш Budget useState при рендеринге (перед возвратом), если он поддерживает правильный массив (не вложенный). Пока ваш Budget имеет правильную структуру данных [{...},{...},{...}], этот ответ должен работать, хотя - person Devin Ekadeni; 22.05.2020
comment
О, я понимаю, почему! [...Budget, response.data.budget] должно быть [...Budget, ...response.data.budget]. Вам также нужно распространять данные ответа. - person Heretic Monkey; 22.05.2020
comment
Итак, если мы не добавим оператор распространения в response.data.budget, то каждый запрос GET будет добавлять еще один вложенный массив в Budget, верно? - person traveler316; 22.05.2020