首页 > 解决方案 > React - 变量/范围问题

问题描述

我正在尝试创建一个 React 组件,该组件在安装时获取书籍列表,然后订阅一个集线器,该集线器通过服务器发送事件通知 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.onmessageIt 调用updateBookList[]进入控制台。它应该返回一个填充的数组,但事实并非如此。

似乎不是使用 的当前值books,而是使用books初始值。

标签: reactjseventsscope

解决方案


我对 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;

推荐阅读