diff --git a/packages/pl-fe/src/components/parsed-content.tsx b/packages/pl-fe/src/components/parsed-content.tsx index 2ed7bed59..a481f931f 100644 --- a/packages/pl-fe/src/components/parsed-content.tsx +++ b/packages/pl-fe/src/components/parsed-content.tsx @@ -1,6 +1,6 @@ import parse, { Element, type HTMLReactParserOptions, domToReact, type DOMNode } from 'html-react-parser'; import DOMPurify from 'isomorphic-dompurify'; -import React, { useMemo } from 'react'; +import React from 'react'; import { Link } from 'react-router-dom'; import Emojify from 'pl-fe/features/emoji/emojify'; @@ -26,98 +26,96 @@ interface IParsedContent { emojis?: Array; } -const ParsedContent: React.FC = (({ html, mentions, hasQuote, emojis }) => { - return useMemo(() => { - if (html.length === 0) { - return null; - } +const ParsedContent: React.FC = React.memo(({ html, mentions, hasQuote, emojis }) => { + if (html.length === 0) { + return null; + } - const emojiMap = emojis ? makeEmojiMap(emojis) : undefined; + const emojiMap = emojis ? makeEmojiMap(emojis) : undefined; - const selectors: Array = []; + const selectors: Array = []; - // Explicit mentions - if (mentions) selectors.push('recipients-inline'); + // Explicit mentions + if (mentions) selectors.push('recipients-inline'); - // Quote posting - if (hasQuote) selectors.push('quote-inline'); + // Quote posting + if (hasQuote) selectors.push('quote-inline'); - const options: HTMLReactParserOptions = { - replace(domNode) { - if (!(domNode instanceof Element)) { - return; - } + const options: HTMLReactParserOptions = { + replace(domNode) { + if (!(domNode instanceof Element)) { + return; + } - if (['script', 'iframe'].includes(domNode.name)) { - return <>; - } + if (['script', 'iframe'].includes(domNode.name)) { + return <>; + } - if (domNode.attribs.class?.split(' ').some(className => selectors.includes(className))) { - return <>; - } + if (domNode.attribs.class?.split(' ').some(className => selectors.includes(className))) { + return <>; + } - if (domNode.name === 'a') { - const classes = domNode.attribs.class?.split(' '); + if (domNode.name === 'a') { + const classes = domNode.attribs.class?.split(' '); - const fallback = ( - // eslint-disable-next-line jsx-a11y/no-static-element-interactions - e.stopPropagation()} - rel='nofollow noopener' - target='_blank' - title={domNode.attribs.href} - > - {domToReact(domNode.children as DOMNode[], options)} - - ); + const fallback = ( + // eslint-disable-next-line jsx-a11y/no-static-element-interactions + e.stopPropagation()} + rel='nofollow noopener' + target='_blank' + title={domNode.attribs.href} + > + {domToReact(domNode.children as DOMNode[], options)} + + ); - if (classes?.includes('mention')) { - if (mentions) { - const mention = mentions.find(({ url }) => domNode.attribs.href === url); - if (mention) { - return ( - - e.stopPropagation()} - > - @{mention.username} - - - ); - } - } else if (domNode.attribs['data-user']) { + if (classes?.includes('mention')) { + if (mentions) { + const mention = mentions.find(({ url }) => domNode.attribs.href === url); + if (mention) { return ( - + + e.stopPropagation()} + > + @{mention.username} + + ); } + } else if (domNode.attribs['data-user']) { + return ( + + ); } - - if (classes?.includes('hashtag')) { - const hashtag = nodesToText(domNode.children as Array); - if (hashtag) { - return ; - } - } - - return fallback; - } - }, - - transform(reactNode, _domNode, index) { - if (typeof reactNode === 'string') { - return ; } - return reactNode as JSX.Element; - }, - }; + if (classes?.includes('hashtag')) { + const hashtag = nodesToText(domNode.children as Array); + if (hashtag) { + return ; + } + } - return parse(DOMPurify.sanitize(html, { ADD_ATTR: ['target'], USE_PROFILES: { html: true } }), options); - }, [html]); -}); + return fallback; + } + }, + + transform(reactNode, _domNode, index) { + if (typeof reactNode === 'string') { + return ; + } + + return reactNode as JSX.Element; + }, + }; + + return parse(DOMPurify.sanitize(html, { ADD_ATTR: ['target'], USE_PROFILES: { html: true } }), options); +}, (prevProps, nextProps) => prevProps.html === nextProps.html); export { ParsedContent }; diff --git a/packages/pl-fe/src/features/emoji/emojify.tsx b/packages/pl-fe/src/features/emoji/emojify.tsx index 909a56c3e..3afd548bf 100644 --- a/packages/pl-fe/src/features/emoji/emojify.tsx +++ b/packages/pl-fe/src/features/emoji/emojify.tsx @@ -33,7 +33,7 @@ interface IEmojify { emojis?: Array | Record; } -const Emojify: React.FC = ({ text, emojis = {} }) => React.useMemo(() => { +const Emojify: React.FC = React.memo(({ text, emojis = {} }) => { if (Array.isArray(emojis)) emojis = makeEmojiMap(emojis); const nodes = []; @@ -102,6 +102,6 @@ const Emojify: React.FC = ({ text, emojis = {} }) => React.useMemo(() if (stack.length) nodes.push(stack); return nodes; -}, [text, emojis]); +}); export { Emojify as default };