You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中Promise处于Pending状态导致无法创建li元素的问题及相关技术疑问

Let's break down your issues one by one and fix your code step by step:

1. Why your async/await function returns a Promise instead of the result

Async functions in JavaScript always return a Promise, no matter what value you return inside them. Even if you return a plain string or array, it gets wrapped in a resolved Promise automatically—that's just how the async/await syntax works under the hood.

On top of that, you're using an async function directly as your useEffect callback. useEffect expects the callback to either return nothing or a cleanup function. When you pass an async function, it returns a Promise, which React can't interpret as a cleanup function—this is a hidden bug in your current code.

2. Fixing the data fetching logic to populate chat correctly

Your main problem right now is that you're setting chat to res.json(), which is a Promise (not the actual array of messages). Plus, you aren't waiting for res.json() to finish parsing the response. Here's how to fix this useEffect:

useEffect(() => {
  let mounted = true;

  const fetchChatHistory = async () => {
    try {
      const response = await fetch("http://localhost:4000/main_chat");
      // Add a check for successful HTTP response
      if (!response.ok) throw new Error(`Failed to fetch: ${response.status}`);
      
      if (mounted) {
        const chatData = await response.json(); // Wait for JSON parsing to complete
        setChat(chatData); // Now setChat gets the actual array, not a Promise
      }
    } catch (error) {
      console.error("Error loading chat history:", error);
    }
  };

  fetchChatHistory();

  return () => {
    mounted = false;
  };
}, []);

Key changes here:

  • We define an async function inside useEffect instead of making the useEffect callback itself async. This avoids returning a Promise to React.
  • We await response.json() because parsing the response body as JSON is an asynchronous operation.
  • Added error handling with try/catch to catch network issues or invalid responses—critical for real-world apps.

3. Rendering the chat messages (fixing the <li> creation)

Right now, you're just logging chat in the <ul>. Once chat is an array, you can map over it to create <li> elements. Since your initial chat state is an empty array, you don't need extra guard clauses, but here's how to render the messages:

<ul>
  {chat.map((message, index) => (
    <li key={index}>{message}</li>
  ))}
</ul>

Note: Using index as a key works fine here if your messages don't have unique IDs and their order doesn't change. For production, use a unique identifier (like a message ID from your backend) if available.

4. Answers to your specific questions

  • How to access the Promise object? You don't need to access the Promise directly here—you want its resolved value (the array of messages). If you ever end up with a Promise in state (which you should avoid), you'd use .then() or await to get its value, but in React, we always wait for Promises to resolve before updating state.
  • How to map over a Promise? You can't map over a Promise directly. You have to wait for it to resolve to an array first, then map over that array. That's exactly what our fixed useEffect does: once we have the parsed array, we put it in state, and then we can safely map over it in the render.

Full corrected code

import { io } from "socket.io-client";
import { useState, useEffect } from "react";

function App() {
  const [text, setText] = useState("");
  const [socket, setSocket] = useState();
  const [chat, setChat] = useState([]);

  // Initialize socket connection
  useEffect(() => {
    const newSocket = io("http://localhost:4000");
    setSocket(newSocket);

    return () => {
      newSocket.close();
    };
  }, []);

  // Fetch previous chat history for new users
  useEffect(() => {
    let mounted = true;

    const fetchChatHistory = async () => {
      try {
        const response = await fetch("http://localhost:4000/main_chat");
        if (!response.ok) throw new Error(`HTTP error! Status: ${response.status}`);
        
        const chatData = await response.json();
        if (mounted) setChat(chatData);
      } catch (error) {
        console.error("Failed to load chat history:", error);
      }
    };

    fetchChatHistory();

    return () => {
      mounted = false;
    };
  }, []);

  // Handle incoming socket messages
  useEffect(() => {
    if (!socket) return;

    socket.on("sentFromServer", (message) => {
      setChat(prevChat => [...prevChat, message]);
    });

    return () => {
      socket.off("sentFromServer");
    };
  }, [socket]);

  const handleClick = () => {
    if (socket && text.trim()) {
      socket.emit("sentFromClient", text);
      setText(""); // Clear input after sending
    }
  };

  return (
    <div>
      <ul>
        {chat.map((message, index) => (
          <li key={index}>{message}</li>
        ))}
      </ul>
      <input
        value={text}
        onChange={(e) => setText(e.target.value)}
        placeholder="Type your message..."
      />
      <button onClick={handleClick}>Send</button>
    </div>
  );
}

export default App;

内容的提问来源于stack exchange,提问作者imback0526

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 06:48:30