quantizor / markdown-to-jsx

🏭 The most lightweight, customizable React markdown component.
https://markdown-to-jsx.quantizor.dev/
MIT License
1.96k stars 169 forks source link

Component is rendering too frequently, when dependencies have not changed #565

Closed neaumusic closed 5 months ago

neaumusic commented 5 months ago
type MarkdownChatMessageProps = {
  markdownOptions: {};
  messageText: string;
};
export const MarkdownChatMessage: FC<MarkdownChatMessageProps> = ({
  markdownOptions,
  messageText,
}) => {
  const markdownComponent = useMemo(() => {
    return <Markdown options={markdownOptions}>{messageText}</Markdown>;
  }, [markdownOptions, messageText]);

  return <ChatMessage>{markdownComponent}</ChatMessage>;
};

We had to simplify our code way down to figure out what was going on. The above code (useMemo on the component) is required for us to prevent tons of re-rendering (janky page on type and hover when we have a very long chat log). When ancestor context state values change, the Markdown component is definitely running a ton of expensive code.

Our use case -- something like 50 chat messages of markdown blog post examples in a Chat GPT style before it becomes unbearable as the user types or hovers around the UI etc

I would expect if markdownOptions is === previous markdownOptions and messageText === previous messageText, it should not be re-rendering, but instead we're required to wrap the component in useMemo!

I did check that the parent/component are only mounting once (useEffect(() => {} []), and I think it simply has to do with changing ancestor context value state, which aren't dependencies for this component. These would be our own state context, and probably @emotion/react theme context.


This is markdown-to-jsx@^7.3.2: resolved to 7.3.2, I briefly checked the releases and didn't see anything specific to this issue, hopefully it makes sense and is reproducible

neaumusic commented 5 months ago

Current thinking is that our markdownOptions components are dependent on the emotion theme, which was causing re-renders, going to close for now