Реагировать - проблема переменной / области - PullRequest
0 голосов
/ 22 февраля 2020

Я пытаюсь создать компонент React, который onMount извлекает список книг, а затем подписывается на концентратор, который уведомляет React о любых изменениях в наборе данных через события, отправленные сервером.

У меня проблемы со следующим кодом:

import React, {useEffect, useState} from 'react';

const BookList = () => {
  const [books, setBooks] = useState([]);

  const getBooks = async () => {
    const response = await fetch('https://localhost:8443/books.jsonld');
    const data = await response.json();
    setBooks(data['hydra:member']);

    ...
    const hub = new URL(hubUrl[1]);
    ...
    const eventSource = new EventSource(hub);
    eventSource.onmessage = (event) => {
      updateBookList(JSON.parse(event.data));
    }
  };

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

  const updateBookList = () => {
    console.log(books);
  };

  return (
    <table>
      <tbody>
      {books.map((book) => (
        <tr key={book['@id']}>
          <td onClick={updateBookList}>{book.name}</td>
        </tr>
      ))}
      </tbody>
    </table>
  )
};
export default BookList;

При загрузке страницы books устанавливается на [] Затем он выбирает данные из API и устанавливает books = [ {}, {}, {}...]

Если я нажимаю на название книги, оно вызывает updateBookList, и я получаю [ {}, {}, {}...] в консоли.

В этот момент, если я запускаю eventSource.onmessage, оно вызывает updateBookList и я получаю [] в консоли. Он должен возвращать заполненный массив, но это не так.

Похоже, что вместо использования текущего значения books он использует books начальное значение.

1 Ответ

0 голосов
/ 23 февраля 2020

Я был озадачен тем, как работает useEffect. Вот решение, которое я нашел:

import React, {useEffect, useState} from 'react';

const BookList = (props) => {
  const [books, setBooks] = useState([]);
  const [eventSource, setEventSource] = useState();

  const getBooks = async () => {
    const response = await fetch(props.url);
    const fetchData = await response.json();

    props.setData(fetchData['hydra:member']);

    ...
    const hub = new URL(hubUrl[1]);
    ...
    setEventSource(new EventSource(hub));
  };

  const updateBookList = () => {
    console.log(books);
  };

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

  useEffect( () => {
    if(eventSource) {
      eventSource.onmessage = (event) => {
        updateBookList(JSON.parse(event.data));
      };
      return () => {
        eventSource.close();
      }
    }
  });

  return (
    <table>
      <tbody>
      {books.map((book) => (
        <tr key={book['@id']}>
          <td onClick={updateBookList}>{book.name}</td>
        </tr>
      ))}
      </tbody>
    </table>
  )
};
export default DataSource;
...