Как оптимизировать результаты вычислений с помощью useMemo?

Рейтинг: 0Ответов: 2Опубликовано: 13.07.2023

Есть компонент, который делает две дорогие по времени операции собирает на лету svg в виде html литерала и парсит этот литерал в реакт компонент. Хочу оптимизировать его с помощью useMemo но не понимаю как, не очень уверенно пока пользуюсь этих хуком. :(

import {FC, useState, useEffect } from 'react'
import parse from 'html-react-parser'

import { getRenderAsString } from './svg-data.builder'
import { ITartanPattern } from './types'

type JSXVariants = JSX.Element | JSX.Element[] | string

const parseSVG = async (data:any):Promise<JSXVariants> => {
  return new Promise( resolve => {
    const parsedData = parse(data)
    resolve(parsedData)
  })
}

const TartanPattern:FC<ITartanPattern> = ({colors}) => {

  const [svgData, setSvgData] = useState('')
  const [element, setElement] = useState<JSXVariants>('')

  useEffect(() => {

    const fetchData = async () => {
      // expensive content generation 
      const newSvgData = await getRenderAsString(colors)
      setSvgData(newSvgData)
    }
    
    fetchData()
    
  }, [colors])

  useEffect(() => {
      const fetchData = async () => {
      // expensive parsing  
      const newElement = await parseSVG(svgData)
        setElement(newElement)
      }

      fetchData()

  }, [svgData])
  
  return (
    <>
    {element}
    </>
  )
}

export default TartanPattern 

Ответы

▲ 0

Вечер добрый:)

Вы можете оптимизировать свой код, благодаря объединению двух дорогих по времени операций в одну.

useEffect(() => {
  const fetchData = async () => {
    // Expensive svg generation
    const newSvgData = await getRenderAsString(colors);
    // Expensive parsing
    const newElement = await parseSVG(newSvgData);
    setElement(newElement);
  };

  fetchData();
}, [colors]);

Комбинируя эти две операции, вы устраняете ненужные повторные рендеринги, вызванные несколькими вызовами useEffect. Таким образом, дорогостоящие операции будут выполняться только один раз при изменении свойства цветов.

Также, чтобы пользователю было понятно, что происходит какое-то действие, можно добавить loader на время выполнения операций

const [loading, setLoading] = useState(true);

useEffect(() => {
  const fetchData = async () => {
    setLoading(true);
    const newSvgData = await getRenderAsString(colors);
    const newElement = await parseSVG(newSvgData);
    setElement(newElement);
    setLoading(false);
  };

  fetchData();
}, [colors]);

return (
  <>
    {loading ? <div>Loading...</div> : element}
  </>
);
▲ 0

Есть компонент, который делает две дорогие по времени операции собирает на лету svg в виде html литерала и парсит этот литерал в реакт компонент. Хочу оптимизировать его с помощью useMemo

Поскольку useMemo не работает с асинхронными функциями, можно попробовать оптимизацию таким образом...

// ...
const data = new Map()

const TartanPattern:FC<ITartanPattern> = ({colors}) => {
  // ...

  useEffect(() => {
      if (data.has(svgData)) {
         const val = data.get(svgData)
         setElement(val)
         return
      }
      const fetchData = async () => {
        const newElement = await parseSVG(svgData)
        setElement(newElement)
        data.set(svgData, newElement)
      }

      fetchData()

  }, [svgData])
  
  return (
    <>
    {element}
    </>
  )
}

export default TartanPattern