The incomplete markdown point is the one that always bites. If you run the parser on every chunk, a half arrived code fence or an unclosed bold tag renders as broken output that then snaps into place a chunk later, which looks worse than plain text. The approach that works is to buffer the trailing incomplete line as raw text and only parse up to the last newline, plus debounce the render to every few chunks so React is not re-parsing the whole message on every token. For scroll, stop auto pinning to the bottom the moment the user scrolls up even slightly, otherwise you fight them the whole way down.
The incomplete markdown point is the one that always bites. If you run the parser on every chunk, a half arrived code fence or an unclosed bold tag renders as broken output that then snaps into place a chunk later, which looks worse than plain text. The approach that works is to buffer the trailing incomplete line as raw text and only parse up to the last newline, plus debounce the render to every few chunks so React is not re-parsing the whole message on every token. For scroll, stop auto pinning to the bottom the moment the user scrolls up even slightly, otherwise you fight them the whole way down.