Repository: facebook/react
File: packages/react-server/src/ReactFizzHooks.js (JavaScript)

Code before:
    // Updates were scheduled during the render phase. They are stored in
    // the `renderPhaseUpdates` map. Call the component again, reusing the
    // work-in-progress hooks and applying the additional updates on top. Keep
    // restarting until no more updates are scheduled.
    didScheduleRenderPhaseUpdate = false;
    localIdCounter = 0;
    bufferedChunks = null;
    thenableIndexCounter = 0;
    numberOfReRenders += 1;

    // Start over from the beginning of the list
    workInProgressHook = null;

    children = Component(props, refOrContext);
  }

  if (bufferedChunks !== null) {
    // This component emitted some chunks. They are buffered until it finishes
    // rendering successfully. We can flush them now.
    const task: Task = (currentlyRenderingTask: any);
    const target = task.blockedSegment.chunks;
    // Not sure why Flow complains. If I change it to spread instead of apply,
    // it checks fine.
    // $FlowFixMe[method-unbinding]
    target.push.apply(target, bufferedChunks);
  }

  resetHooksState();
  return children;
}

export function getThenableStateAfterSuspending(): null | ThenableState {
  const state = thenableState;
  thenableState = null;
  return state;
}

export function checkDidRenderIdHook(): boolean {
  // This should be called immediately after every finishHooks call.
  // Conceptually, it's part of the return value of finishHooks; it's only a
  // separate function to avoid using an array tuple.
  const didRenderIdHook = localIdCounter !== 0;
  return didRenderIdHook;
}

// Reset the internal hooks state if an error occurs while rendering a component
export function resetHooksState(): void {
  if (__DEV__) {
    isInHookUserCodeInDev = false;
  }


Review comment (bug):
I'm not sure this is going to work in the edge case

```
function App() {
  let ... = useFormState();
  return (
    <html>
      <body>
        <form ...>
      </body>
    </html>
}
```

In Fizz (with float enabled) the html chunks are sequester so the fact that the comment is getting pushed to the target before the DOCTYPE does accidentally works out (we'll still emit `<DOCTYPE html><html><head><!--F-->`). However when hydrating on the client the starting point for hydration is `document.body` I believe (I can't remember if I made this change or I just talked about making it but conceptually we can start hydration from body b/c everything else is singleton which has it's own hydration path). If hydration starts from the body the form comment will be missed b/c it is in the head.

I don't have a good solution to this problem. We could maybe figure out if we need to put the comment before the `<html>` in the DOM by slotting it just after the DOCTYPE. Then we'd have to also special case the hydration cursor to look there. Additionally I think this may conflict with prerendering b/c we will have a static preamble (the html, head tag, and some head content) even when we can't fully prerender the entire shell. So we may have something dynamic (the form state indictator comment) that needs to be embedded inside the static part which just can't happen

Code after:
    // restarting until no more updates are scheduled.
    didScheduleRenderPhaseUpdate = false;
    localIdCounter = 0;
    formStateCounter = 0;
    formStateMatchingIndex = -1;
    thenableIndexCounter = 0;
    numberOfReRenders += 1;

    // Start over from the beginning of the list
    workInProgressHook = null;

    children = Component(props, refOrContext);
  }

  resetHooksState();
  return children;
}

export function getThenableStateAfterSuspending(): null | ThenableState {
  const state = thenableState;
  thenableState = null;
  return state;
}

export function checkDidRenderIdHook(): boolean {
  // This should be called immediately after every finishHooks call.
  // Conceptually, it's part of the return value of finishHooks; it's only a
  // separate function to avoid using an array tuple.
  const didRenderIdHook = localIdCounter !== 0;
  return didRenderIdHook;
}

export function getFormStateCount(): number {
  // This should be called immediately after every finishHooks call.
  // Conceptually, it's part of the return value of finishHooks; it's only a
  // separate function to avoid using an array tuple.
  return formStateCounter;
}
export function getFormStateMatchingIndex(): number {
  // This should be called immediately after every finishHooks call.
  // Conceptually, it's part of the return value of finishHooks; it's only a
  // separate function to avoid using an array tuple.
  return formStateMatchingIndex;
}

// Reset the internal hooks state if an error occurs while rendering a component
export function resetHooksState(): void {
  if (__DEV__) {
    isInHookUserCodeInDev = false;
  }