Problem description

Use Echarts to generate diagrams in a function component. The general idea is as follows:

function Demo(){
  const [chartData, setChartData] = useState([1.2.3])
  useEffect(updateChart, [chartData])
  let option = {	
    xAxis: {data:[]
      }
      // ...
    }
  
  function updateChart(){
  	option.xAxis.data = chartData
    / /...}}Copy the code

Linter will prompt you to add option to effect’s dependency list. What happens when you add it in? Linter also notes that the dependency on the option variable causes effect to be triggered every time you render, and recommends using useMemo to cache this variable.

The ‘option’ object makes the dependencies of useEffect Hook change on every render. To fix this, wrap the initialization of ‘option’ in its own useMemo() Hook.

If prompted, it would look like this:

useEffect(updateChart, [chartData, option])	/ / add the option
let option = useMemo(() = >({
  xAxis: {data:[]
  }
  // ...}, [])Copy the code

The code should then run normally. The problem, however, is that the return value of the function passed to useMemo is constant, that is, it does not need to be recalculated. Is this really OK?

When to use useMemo?

UseMemo guarantees reference equality of returned values on each render to avoid costly calculations on each render.

Ask yourself three questions before using it:

  1. Passed to theuseMemoIs the function of is really an expensive computation?
  2. Does the reference to the return value change? If you return a variable of an underlying data type (string, Number, Boolean, NULL, undefined, symbol), the reference is never changed.
  3. Does this value need to be recalculated? Such asUseMemo (() = > [1, 2, 3], [])Obviously not.

Optimization method

All you need to do is save a variable and keep references equal between renders. That could have been useRef.

useEffect(updateChart, [chartData])	// No more dependencies need to be added
let optionRef = useRef({	// save option to optionRef.current
  xAxis: {data:[]
  }
  // ...
})
function updateChart(){
  optionRef.current.xAxis.data = chartData	
  / /...
}
Copy the code

The useRef is used to create a mutable REF object that remains constant throughout the life of the component. The ref object’s current can hold any value, not just Dom. Refer to this question in the reading FAQ. So in this case, useRef is perfectly fine.

Conceptually, you can think of refs as being like an instance variable of class.

If you get tired of needing.current every time, just deconstruct it and rename it:

const { current: option } = useRef([1.2.3])
Copy the code

Refer to the reading

You’re overusing useMemo: Rethinking Hooks memoization