1

Question: Why does navigating appear to change the readyState of the previous EventSources?

===============================================

Explanation: I'm working on a frontend (React) in which the user can enter a sequence of search queries (i.e. strings) and for each search query, my backend (Flask) will return a sequence of URLs. For each search query, I've decided to receive the server's response via an EventSource. Specifically, I first create a React state array of backendEventSources:

const [backendEventSources, setBackendEventSources] = useState([]);

Then I update the backendEventSources when a new prompt comes in:

  useEffect(() => {

    console.log('Inside useEffect')

    // Take 0 for the newest prompt.
    const newBackendEventSource = new EventSource(
      `https://localhost:8080/generate?counter=${promptsResultsArray[0].counter}&prompt=${promptsResultsArray[0].prompt}`,
      {withCredentials: false})

    newBackendEventSource.addEventListener('open', () => {
      console.log('SSE opened!');
    });

    newBackendEventSource.addEventListener('error', (e) => {
      console.log('SSE error!');
      console.error('Error: ',  e);
    });

    newBackendEventSource.addEventListener('close', (e) => {
      console.log('SSE closed!');
      const data = JSON.parse(e.data);
      console.log("close data: ", data);
      newBackendEventSource.close();
    });

    newBackendEventSource.addEventListener('message', (e) => {
      const data = JSON.parse(e.data);
      console.log("message data: ", data);
      // https://stackoverflow.com/a/47580775/4570472
      const newPromptsResultsArray = [...promptsResultsArray];
      // Since we preprend new results, we need to compute the right index from
      // the counter with the equation: length - counter - 1.
      // e.g., For counter 2 of a length 3 array, we want index 0.
      // e.g., For counter 2 of a length 4 array, we want index 1.
      // Recall, the counter uses 0-based indexing.
      const index = newPromptsResultsArray.length - data.counter - 1
      newPromptsResultsArray[index].URIs = [data.uri];
      newPromptsResultsArray[index].isLoading = false;
      setPromptsResultsArray(newPromptsResultsArray);

      // Instantiating the element and setting the src property starts preloading the image.
      // for (const newImgURI of newImgURIs) {
      //   const imageElement = new Image();
      //   imageElement.src = newImgURI;
      // }
      // setTimeout(() => {setImgURIs(newImgURIs)}, 8000);
    });

    // Add new backend event source to state for persistence.
    setBackendEventSources(backendEventSources => [
      newBackendEventSource,
      ...backendEventSources])

    return () => {
      newBackendEventSource.close();
    };

  }, [prompt]);

I use URL params for React navigation:

  const navigateToGenerateResults = (promptString) => {
    console.log('Adding new prompt results to promptsResultsArray');

    // State doesn't update immediately (or even synchronously). To ensure we can immediately
    // access the new values, we create a newPromptsResults.
    // https://stackoverflow.com/a/62900445/4570472
    const newPromptsResults = {
      isLoading: true,
      prompt: promptString,
      counter: promptsResultsArray.length,
      URIs: ["https://simtooreal-public.s3.amazonaws.com/white_background.png"]
    }

    // Prepend the new prompt to our promptsResultsArray
    // https://stackoverflow.com/a/60792858/4570472
    setPromptsResultsArray(promptsResultsArray => [
      newPromptsResults, ...promptsResultsArray])
    console.log('Setting prompt to: ' + newPromptsResults.prompt)
    setPrompt(newPromptsResults.prompt)
    console.log('Navigating from /generate to /generate with prompt: ' + newPromptsResults.prompt)
    navigate(`/generate?counter=${newPromptsResults.counter}&prompt=${newPromptsResults.prompt}`)
  }

However, I've discovered that as soon as I navigate from one URL to another, the previous EventSource's ready state switches from 0/1 to 2. Additionally, my newBackendEventSource.addEventListener('close' function is never triggered.

Why does navigating appear to change the readyState of the previous EventSources?

Rylan Schaeffer
  • 1,945
  • 2
  • 28
  • 50

0 Answers0