.map не работает при возврате функционального компонента React - PullRequest
2 голосов
/ 04 октября 2019

У меня есть компонент реагирования, использующий хуки, где я нажимаю кнопку, чтобы сделать вызовы API для API Hacker News и поместить результаты в массив. Затем я установил состояние «историй», чтобы этот массив был полон историй.

У меня есть вторая функция, запускаемая кнопкой, консоль регистрирует состояние «историй», а консоль .log возвращает .mapназвание каждой историиВсе это работает просто отлично.

Если я попытаюсь использовать .map при возврате компонента, он не будет работать. Если я инициализирую состояние «историй», равное ["test", "test1", "test2"], то .map работает, но как только я нажимаю кнопку, чтобы установить состояние в качестве массива историй, .map перестает работать. Нет сообщений об ошибках, только содержание уходит.

Здесь я импортирую React и устанавливаю исходное состояние. Я использовал Axios, Fetch и Wretch для выполнения вызовов API, все с одинаковыми результатами:

import React, { useState, useEffect } from 'react';
const axios = require('axios');
import wretch from "wretch"


function App () {
    const [stories, setStories] = useState(["test", "test2", "test3"]);

Вотфункция, которую я запускаю, чтобы нажать API и установить состояние:

function call () {
        let storiesArr = [];
        fetch('http://hacker-news.firebaseio.com/v0/topstories.json')
            .then ((res) => res.json())
            .then ((data) => {
                for (let i = 0; i < 20; i++) {
                    fetch(`http://hacker-news.firebaseio.com/v0/item/${data[i]}.json`)
                    .then((res) => res.json())
                    .then((eachStory) => {
                        storiesArr.push(eachStory);
                    })
                }
            })

Вот вторая функция, которую я использую, чтобы проверить, что состояние было установлено с тем, что я думаю, и убедиться, чточто .map работает в состоянии «историй». Это работает для меня:

    function test () {
        console.log(stories);

       stories.map((each) => {
            return <p>{each.title}</p>
        })
    }

Это мое возвращение, .map здесь работает с начальным состоянием, но не один раз, когда я устанавливаю состояние в качестве нового массива:

return (
           <>
                <h1 onClick={ () => call() } className="click">Fire off API calls</h1>
                <h1 onClick={ () => test() } className="click">Test state of stories/<br/>.map each title</h1>
                <table className="table">
                    <thead>
                        <tr>
                            <td>Table</td>
                        </tr>
                    </thead>
                    <tbody>
                           {
                                stories.map((each, i) => {
                                    return <tr key={i}>
                                            <td>{each.title ? each.title : each}</td>
                                        </tr>
                            })
                           }
                    </tbody>
                </table>

           </>
        );

Я не могу понять, почему .map сначала работает, больше не работает в возврате, но работает в функции ....

Я был бы очень признателен за любую помощь, которая может быть.

Ответы [ 2 ]

1 голос
/ 04 октября 2019

Я думаю, что это скорее проблема асинхронной обработки, чем setState. Вот удобный пример все в одном (упрощенный)

import React, { useState } from "react";
import ReactDOM from "react-dom";

// gets list of article ids
const getStoryList = async () => {
  const res = await fetch(
    "https://hacker-news.firebaseio.com/v0/topstories.json"
  );

  return await res.json();
};

// iterates over article list and returns a promise.all
const getStories = (articles, quantity) => {
  return Promise.all(
    articles.slice(0, quantity).map(async article => {
      const storyRes = await fetch(
        `https://hacker-news.firebaseio.com/v0/item/${article}.json`
      );

      return await storyRes.json();
    })
  );
};

// maps your response data
const formatStories = stories =>
  stories.map(({ by, id, url, title = "No Title" }) => ({
    id,
    title,
    url,
    by
  }));

function App() {
  const [stories, setStories] = useState([]);

  const call = async () => {
    // first get list of stories
    const res = await getStoryList();
    // then async request all of the individual articles
    // and push them into a group of promises
    const storiesArr = await getStories(res, 20);
    // then set your state.
    setStories(formatStories(storiesArr));
  };

  return (
    <div className="App">
      <button onClick={call} className="click">
        Fire off API calls
      </button>

      <table className="table">
        <thead>
          <tr>
            <td>Table</td>
          </tr>
        </thead>
        <tbody>
          {stories.map(story => {
            return (
              <tr key={story.id}>
                <td>
                  <a href={story.url}>{story.title}</a> by {story.by}
                </td>
              </tr>
            );
          })}
        </tbody>
      </table>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
1 голос
/ 04 октября 2019

Ваша выборка данных выглядит немного сумбурно, вы знаете, что вы можете использовать Promise.all вместо отправки в массив и зацикливания.

Я добавил проверку , чтобы увидеть, если компонентвсе еще смонтирован перед установкой состояния.

const isMounted = useIsMounted();
//other code, I imagine useEfffect
function call() {
  fetch(
    'http://hacker-news.firebaseio.com/v0/topstories.json'
  )
    .then(res => res.json())
    .then(data =>
      Promise.all(
        data.map(item =>
          fetch(
            `http://hacker-news.firebaseio.com/v0/item/${item}.json`
          ).then(res => res.json())
        )
      )
    )
    .then(
      result => isMounted.current && setStories(result)
    );
}

Также: http://hacker -news.firebaseio.com / v0 / topstories.json возвращает более 400 элементов, которые заставят вас сделатьболее 400 запросов для каждого элемента, я не думаю, что хакерские новости оценят это, поэтому, возможно, нарежут результат и / или разместят его на странице.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...