Removing the tileFactory from components props (to limit re-renderings).

This commit is contained in:
Eric van der Vlist 2022-10-29 21:16:50 +02:00
parent 4479b1bd99
commit 7f9400b395
4 changed files with 180 additions and 94 deletions

View File

@ -35,15 +35,6 @@ export const LayerStack: react.FC<LayerStackProperties> = (
) => { ) => {
const [coordinateSystem] = useAtom(coordinateSystemAtom); const [coordinateSystem] = useAtom(coordinateSystemAtom);
const simpleTileFactory: TileFactory = useCallback(
(keyObject) => (
<Tile
href={`https://tile.openstreetmap.org/${keyObject.zoomLevel}/${keyObject.x}/${keyObject.y}.png`}
/>
),
[]
);
const numberOfTiledLayers = const numberOfTiledLayers =
props.numberOfTiledLayers === undefined ? 1 : props.numberOfTiledLayers; props.numberOfTiledLayers === undefined ? 1 : props.numberOfTiledLayers;
@ -107,7 +98,6 @@ export const LayerStack: react.FC<LayerStackProperties> = (
key={key} key={key}
keyObject={keyObject} keyObject={keyObject}
viewPort={i === activeTiledLayer ? viewPort : undefined} viewPort={i === activeTiledLayer ? viewPort : undefined}
tileFactory={simpleTileFactory}
/> />
</g> </g>
); );

View File

@ -2,10 +2,6 @@ import { render } from '@testing-library/react';
import TiledLayer from './TiledLayer'; import TiledLayer from './TiledLayer';
import { TileFactory } from './types'; import { TileFactory } from './types';
const fakeTileFactory: TileFactory = (keyObject) => (
<text>{JSON.stringify(keyObject)}</text>
);
describe('The TiledLayer component ', () => { describe('The TiledLayer component ', () => {
beforeEach(() => { beforeEach(() => {
globalThis.cacheForTiledLayer = new Map(); globalThis.cacheForTiledLayer = new Map();
@ -17,7 +13,6 @@ describe('The TiledLayer component ', () => {
<TiledLayer <TiledLayer
keyObject={{ provider: 'osm', zoomLevel: 10, x: 5, y: 8 }} keyObject={{ provider: 'osm', zoomLevel: 10, x: 5, y: 8 }}
viewPort={{ topLeft: { x: 1, y: 2 }, bottomRight: { x: 3, y: 2 } }} viewPort={{ topLeft: { x: 1, y: 2 }, bottomRight: { x: 3, y: 2 } }}
tileFactory={fakeTileFactory}
/> />
</svg> </svg>
); );
@ -29,23 +24,35 @@ describe('The TiledLayer component ', () => {
<g <g
transform="translate(1, 2)" transform="translate(1, 2)"
> >
<text> <g>
{"provider":"osm","zoomLevel":10,"x":6,"y":10} <image
</text> height="1"
href="https://tile.openstreetmap.org/10/6/10.png"
width="1"
/>
</g>
</g> </g>
<g <g
transform="translate(2, 2)" transform="translate(2, 2)"
> >
<text> <g>
{"provider":"osm","zoomLevel":10,"x":7,"y":10} <image
</text> height="1"
href="https://tile.openstreetmap.org/10/7/10.png"
width="1"
/>
</g>
</g> </g>
<g <g
transform="translate(3, 2)" transform="translate(3, 2)"
> >
<text> <g>
{"provider":"osm","zoomLevel":10,"x":8,"y":10} <image
</text> height="1"
href="https://tile.openstreetmap.org/10/8/10.png"
width="1"
/>
</g>
</g> </g>
</svg> </svg>
</div> </div>
@ -59,7 +66,6 @@ describe('The TiledLayer component ', () => {
<TiledLayer <TiledLayer
keyObject={{ provider: 'osm', zoomLevel: 10, x: 5, y: 8 }} keyObject={{ provider: 'osm', zoomLevel: 10, x: 5, y: 8 }}
viewPort={{ topLeft: { x: 1, y: 2 }, bottomRight: { x: 3, y: 2 } }} viewPort={{ topLeft: { x: 1, y: 2 }, bottomRight: { x: 3, y: 2 } }}
tileFactory={fakeTileFactory}
/> />
</svg> </svg>
); );
@ -68,7 +74,6 @@ describe('The TiledLayer component ', () => {
<TiledLayer <TiledLayer
keyObject={{ provider: 'osm', zoomLevel: 10, x: 5, y: 8 }} keyObject={{ provider: 'osm', zoomLevel: 10, x: 5, y: 8 }}
viewPort={{ topLeft: { x: 5, y: 0 }, bottomRight: { x: 5, y: 2 } }} viewPort={{ topLeft: { x: 5, y: 0 }, bottomRight: { x: 5, y: 2 } }}
tileFactory={fakeTileFactory}
/> />
</svg> </svg>
); );
@ -80,44 +85,68 @@ describe('The TiledLayer component ', () => {
<g <g
transform="translate(1, 2)" transform="translate(1, 2)"
> >
<text> <g>
{"provider":"osm","zoomLevel":10,"x":6,"y":10} <image
</text> height="1"
href="https://tile.openstreetmap.org/10/6/10.png"
width="1"
/>
</g>
</g> </g>
<g <g
transform="translate(2, 2)" transform="translate(2, 2)"
> >
<text> <g>
{"provider":"osm","zoomLevel":10,"x":7,"y":10} <image
</text> height="1"
href="https://tile.openstreetmap.org/10/7/10.png"
width="1"
/>
</g>
</g> </g>
<g <g
transform="translate(3, 2)" transform="translate(3, 2)"
> >
<text> <g>
{"provider":"osm","zoomLevel":10,"x":8,"y":10} <image
</text> height="1"
href="https://tile.openstreetmap.org/10/8/10.png"
width="1"
/>
</g>
</g> </g>
<g <g
transform="translate(5, 0)" transform="translate(5, 0)"
> >
<text> <g>
{"provider":"osm","zoomLevel":10,"x":10,"y":8} <image
</text> height="1"
href="https://tile.openstreetmap.org/10/10/8.png"
width="1"
/>
</g>
</g> </g>
<g <g
transform="translate(5, 1)" transform="translate(5, 1)"
> >
<text> <g>
{"provider":"osm","zoomLevel":10,"x":10,"y":9} <image
</text> height="1"
href="https://tile.openstreetmap.org/10/10/9.png"
width="1"
/>
</g>
</g> </g>
<g <g
transform="translate(5, 2)" transform="translate(5, 2)"
> >
<text> <g>
{"provider":"osm","zoomLevel":10,"x":10,"y":10} <image
</text> height="1"
href="https://tile.openstreetmap.org/10/10/10.png"
width="1"
/>
</g>
</g> </g>
</svg> </svg>
</div> </div>
@ -130,7 +159,6 @@ describe('The TiledLayer component ', () => {
<TiledLayer <TiledLayer
keyObject={{ provider: 'osm', zoomLevel: 10, x: 5, y: 8 }} keyObject={{ provider: 'osm', zoomLevel: 10, x: 5, y: 8 }}
viewPort={{ topLeft: { x: 1, y: 2 }, bottomRight: { x: 3, y: 2 } }} viewPort={{ topLeft: { x: 1, y: 2 }, bottomRight: { x: 3, y: 2 } }}
tileFactory={fakeTileFactory}
/> />
</svg> </svg>
); );
@ -139,7 +167,6 @@ describe('The TiledLayer component ', () => {
<TiledLayer <TiledLayer
keyObject={{ provider: 'osm', zoomLevel: 10, x: 4, y: 10 }} keyObject={{ provider: 'osm', zoomLevel: 10, x: 4, y: 10 }}
viewPort={{ topLeft: { x: 5, y: 0 }, bottomRight: { x: 5, y: 2 } }} viewPort={{ topLeft: { x: 5, y: 0 }, bottomRight: { x: 5, y: 2 } }}
tileFactory={fakeTileFactory}
/> />
</svg> </svg>
); );
@ -151,44 +178,68 @@ describe('The TiledLayer component ', () => {
<g <g
transform="translate(1, 2)" transform="translate(1, 2)"
> >
<text> <g>
{"provider":"osm","zoomLevel":10,"x":6,"y":10} <image
</text> height="1"
href="https://tile.openstreetmap.org/10/6/10.png"
width="1"
/>
</g>
</g> </g>
<g <g
transform="translate(2, 2)" transform="translate(2, 2)"
> >
<text> <g>
{"provider":"osm","zoomLevel":10,"x":7,"y":10} <image
</text> height="1"
href="https://tile.openstreetmap.org/10/7/10.png"
width="1"
/>
</g>
</g> </g>
<g <g
transform="translate(3, 2)" transform="translate(3, 2)"
> >
<text> <g>
{"provider":"osm","zoomLevel":10,"x":8,"y":10} <image
</text> height="1"
href="https://tile.openstreetmap.org/10/8/10.png"
width="1"
/>
</g>
</g> </g>
<g <g
transform="translate(5, 0)" transform="translate(5, 0)"
> >
<text> <g>
{"provider":"osm","zoomLevel":10,"x":9,"y":10} <image
</text> height="1"
href="https://tile.openstreetmap.org/10/9/10.png"
width="1"
/>
</g>
</g> </g>
<g <g
transform="translate(5, 1)" transform="translate(5, 1)"
> >
<text> <g>
{"provider":"osm","zoomLevel":10,"x":9,"y":11} <image
</text> height="1"
href="https://tile.openstreetmap.org/10/9/11.png"
width="1"
/>
</g>
</g> </g>
<g <g
transform="translate(5, 2)" transform="translate(5, 2)"
> >
<text> <g>
{"provider":"osm","zoomLevel":10,"x":9,"y":12} <image
</text> height="1"
href="https://tile.openstreetmap.org/10/9/12.png"
width="1"
/>
</g>
</g> </g>
</svg> </svg>
</div> </div>
@ -201,7 +252,6 @@ describe('The TiledLayer component ', () => {
<TiledLayer <TiledLayer
keyObject={{ provider: 'osm', zoomLevel: 10, x: 5, y: 8 }} keyObject={{ provider: 'osm', zoomLevel: 10, x: 5, y: 8 }}
viewPort={{ topLeft: { x: -3, y: -1 }, bottomRight: { x: -2, y: 2 } }} viewPort={{ topLeft: { x: -3, y: -1 }, bottomRight: { x: -2, y: 2 } }}
tileFactory={fakeTileFactory}
/> />
</svg> </svg>
); );
@ -213,58 +263,90 @@ describe('The TiledLayer component ', () => {
<g <g
transform="translate(-3, -1)" transform="translate(-3, -1)"
> >
<text> <g>
{"provider":"osm","zoomLevel":10,"x":2,"y":7} <image
</text> height="1"
href="https://tile.openstreetmap.org/10/2/7.png"
width="1"
/>
</g>
</g> </g>
<g <g
transform="translate(-2, -1)" transform="translate(-2, -1)"
> >
<text> <g>
{"provider":"osm","zoomLevel":10,"x":3,"y":7} <image
</text> height="1"
href="https://tile.openstreetmap.org/10/3/7.png"
width="1"
/>
</g>
</g> </g>
<g <g
transform="translate(-3, 0)" transform="translate(-3, 0)"
> >
<text> <g>
{"provider":"osm","zoomLevel":10,"x":2,"y":8} <image
</text> height="1"
href="https://tile.openstreetmap.org/10/2/8.png"
width="1"
/>
</g>
</g> </g>
<g <g
transform="translate(-2, 0)" transform="translate(-2, 0)"
> >
<text> <g>
{"provider":"osm","zoomLevel":10,"x":3,"y":8} <image
</text> height="1"
href="https://tile.openstreetmap.org/10/3/8.png"
width="1"
/>
</g>
</g> </g>
<g <g
transform="translate(-3, 1)" transform="translate(-3, 1)"
> >
<text> <g>
{"provider":"osm","zoomLevel":10,"x":2,"y":9} <image
</text> height="1"
href="https://tile.openstreetmap.org/10/2/9.png"
width="1"
/>
</g>
</g> </g>
<g <g
transform="translate(-2, 1)" transform="translate(-2, 1)"
> >
<text> <g>
{"provider":"osm","zoomLevel":10,"x":3,"y":9} <image
</text> height="1"
href="https://tile.openstreetmap.org/10/3/9.png"
width="1"
/>
</g>
</g> </g>
<g <g
transform="translate(-3, 2)" transform="translate(-3, 2)"
> >
<text> <g>
{"provider":"osm","zoomLevel":10,"x":2,"y":10} <image
</text> height="1"
href="https://tile.openstreetmap.org/10/2/10.png"
width="1"
/>
</g>
</g> </g>
<g <g
transform="translate(-2, 2)" transform="translate(-2, 2)"
> >
<text> <g>
{"provider":"osm","zoomLevel":10,"x":3,"y":10} <image
</text> height="1"
href="https://tile.openstreetmap.org/10/3/10.png"
width="1"
/>
</g>
</g> </g>
</svg> </svg>
</div> </div>

View File

@ -3,6 +3,7 @@ import { range, isEqual } from 'lodash';
import { Rectangle, TileFactory, TileKeyObject } from './types'; import { Rectangle, TileFactory, TileKeyObject } from './types';
import tileUri from './uris'; import tileUri from './uris';
import tileFactory from './tile-factory';
/** /**
* @hidden * @hidden
@ -26,8 +27,6 @@ export interface TiledLayerProperties {
keyObject: TileKeyObject; keyObject: TileKeyObject;
/** The current viewport expressed in tiles coordinates */ /** The current viewport expressed in tiles coordinates */
viewPort?: Rectangle; viewPort?: Rectangle;
/** The factory to create tiles */
tileFactory: TileFactory;
} }
/** /**
@ -49,9 +48,9 @@ export interface TiledLayerProperties {
* Idea stolen [on the web](https://dev.to/tiagof/react-re-mounting-vs-re-rendering-lnh) * Idea stolen [on the web](https://dev.to/tiagof/react-re-mounting-vs-re-rendering-lnh)
* *
* TODO: cache housekeeping * TODO: cache housekeeping
* *
* TODO: test tiles'X and Y boundaries. * TODO: test tiles'X and Y boundaries.
* *
* TODO: remove tileFactory to facilitate memoisation. * TODO: remove tileFactory to facilitate memoisation.
* *
*/ */
@ -84,7 +83,7 @@ export const TiledLayer: react.FC<TiledLayerProperties> = (
tiles.set( tiles.set(
key, key,
<g key={key} transform={`translate(${col}, ${row})`}> <g key={key} transform={`translate(${col}, ${row})`}>
{props.tileFactory(keyObject)} {tileFactory(keyObject)}
</g> </g>
); );
} }

View File

@ -0,0 +1,15 @@
import Tile from './Tile';
import { TileFactory, TileKeyObject } from './types';
/**
*
* @param keyObject The tile identifier
* @returns The `<Tile>` component
*/
export const tileFactory: TileFactory = (keyObject:TileKeyObject) => (
<Tile
href={`https://tile.openstreetmap.org/${keyObject.zoomLevel}/${keyObject.x}/${keyObject.y}.png`}
/>
);
export default tileFactory;