Prefer React.memo to useMemo when memoizing components

This commit is contained in:
Rob Watson 2021-12-04 05:34:17 +01:00
parent 155e41136c
commit e486aab770
5 changed files with 48 additions and 57 deletions

View File

@ -6,7 +6,7 @@ import {
GetAudioProgress, GetAudioProgress,
} from './generated/media_set'; } from './generated/media_set';
import { useState, useEffect, useRef, useMemo } from 'react'; import { useState, useEffect, useRef, useCallback } from 'react';
import { VideoPreview } from './VideoPreview'; import { VideoPreview } from './VideoPreview';
import { Overview, CanvasLogicalWidth } from './Overview'; import { Overview, CanvasLogicalWidth } from './Overview';
import { Waveform } from './Waveform'; import { Waveform } from './Waveform';
@ -178,6 +178,16 @@ function App(): JSX.Element {
video.currentTime = currentTime; video.currentTime = currentTime;
}; };
const handlePlay = useCallback(() => {
audio.play();
video.play();
}, [audio, video]);
const handlePause = useCallback(() => {
video.pause();
audio.pause();
}, [audio, video]);
// render component // render component
const containerStyles = { const containerStyles = {
@ -192,24 +202,6 @@ function App(): JSX.Element {
const offsetPixels = Math.floor(thumbnailWidth / 2); const offsetPixels = Math.floor(thumbnailWidth / 2);
// Avoid re-rendering this component during playback. Needs to be memoized
// before the mediaSet null check below.
const controlBar = useMemo(
() => (
<ControlBar
onPlay={() => {
audio.play();
video.play();
}}
onPause={() => {
video.pause();
audio.pause();
}}
/>
),
[]
);
if (mediaSet == null) { if (mediaSet == null) {
// TODO: improve // TODO: improve
return <></>; return <></>;
@ -219,7 +211,8 @@ function App(): JSX.Element {
<> <>
<div className="App"> <div className="App">
<div style={containerStyles}> <div style={containerStyles}>
{controlBar} <ControlBar onPlay={handlePlay} onPause={handlePause} />
<Overview <Overview
peaks={overviewPeaks} peaks={overviewPeaks}
mediaSet={mediaSet} mediaSet={mediaSet}

View File

@ -1,9 +1,11 @@
import React from 'react';
interface Props { interface Props {
onPlay: () => void; onPlay: () => void;
onPause: () => void; onPause: () => void;
} }
export const ControlBar: React.FC<Props> = (props: Props) => { const ControlBar: React.FC<Props> = React.memo((props: Props) => {
const styles = { width: '100%', flexGrow: 0 }; const styles = { width: '100%', flexGrow: 0 };
const buttonStyles = { const buttonStyles = {
cursor: 'pointer', cursor: 'pointer',
@ -27,4 +29,7 @@ export const ControlBar: React.FC<Props> = (props: Props) => {
</div> </div>
</> </>
); );
}; });
ControlBar.displayName = 'ControlBar';
export { ControlBar };

View File

@ -1,4 +1,4 @@
import { useState, useEffect, useRef, useMemo, MouseEvent } from 'react'; import { useState, useEffect, useRef, MouseEvent } from 'react';
import { MediaSet } from './generated/media_set'; import { MediaSet } from './generated/media_set';
import { Frames, VideoPosition } from './App'; import { Frames, VideoPosition } from './App';
import { WaveformCanvas } from './WaveformCanvas'; import { WaveformCanvas } from './WaveformCanvas';
@ -336,21 +336,16 @@ export const Overview: React.FC<Props> = ({
return ( return (
<> <>
<div style={containerStyles}> <div style={containerStyles}>
{useMemo( <WaveformCanvas
() => ( peaks={peaks}
<WaveformCanvas channels={mediaSet.audioChannels}
peaks={peaks} width={CanvasLogicalWidth}
channels={mediaSet.audioChannels} height={CanvasLogicalHeight}
width={CanvasLogicalWidth} strokeStyle="black"
height={CanvasLogicalHeight} fillStyle="#003300"
strokeStyle="black" zIndex={1}
fillStyle="#003300" alpha={1}
zIndex={1} ></WaveformCanvas>
alpha={1}
></WaveformCanvas>
),
[peaks, mediaSet]
)}
<canvas <canvas
ref={hudCanvasRef} ref={hudCanvasRef}
width={CanvasLogicalWidth} width={CanvasLogicalWidth}

View File

@ -1,4 +1,4 @@
import { useEffect, useState, useRef, useMemo } from 'react'; import { useEffect, useState, useRef } from 'react';
import { Frames, VideoPosition, newRPC } from './App'; import { Frames, VideoPosition, newRPC } from './App';
import { MediaSetServiceClientImpl, MediaSet } from './generated/media_set'; import { MediaSetServiceClientImpl, MediaSet } from './generated/media_set';
import { WaveformCanvas } from './WaveformCanvas'; import { WaveformCanvas } from './WaveformCanvas';
@ -112,21 +112,16 @@ export const Waveform: React.FC<Props> = ({
return ( return (
<> <>
<div style={containerStyles}> <div style={containerStyles}>
{useMemo( <WaveformCanvas
() => ( peaks={peaks}
<WaveformCanvas channels={mediaSet.audioChannels}
peaks={peaks} width={CanvasLogicalWidth}
channels={mediaSet.audioChannels} height={CanvasLogicalHeight}
width={CanvasLogicalWidth} strokeStyle="green"
height={CanvasLogicalHeight} fillStyle="black"
strokeStyle="green" zIndex={0}
fillStyle="black" alpha={1}
zIndex={0} ></WaveformCanvas>
alpha={1}
></WaveformCanvas>
),
[peaks, mediaSet]
)}
<canvas <canvas
width={CanvasLogicalWidth} width={CanvasLogicalWidth}
height={CanvasLogicalHeight} height={CanvasLogicalHeight}

View File

@ -1,4 +1,4 @@
import { useEffect, useRef } from 'react'; import React, { useEffect, useRef } from 'react';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
const maxPeakValue = 32_768; const maxPeakValue = 32_768;
@ -22,7 +22,7 @@ interface Props {
// strokeStyle: waveform style // strokeStyle: waveform style
// fillStyle: background style // fillStyle: background style
// style: React.CSSProperties applied to canvas element // style: React.CSSProperties applied to canvas element
export const WaveformCanvas: React.FC<Props> = (props: Props) => { const WaveformCanvas: React.FC<Props> = React.memo((props: Props) => {
const canvasRef = useRef<HTMLCanvasElement>(null); const canvasRef = useRef<HTMLCanvasElement>(null);
useEffect(() => { useEffect(() => {
@ -89,4 +89,7 @@ export const WaveformCanvas: React.FC<Props> = (props: Props) => {
></canvas> ></canvas>
</> </>
); );
}; });
WaveformCanvas.displayName = 'WaveformCanvas';
export { WaveformCanvas };