-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: optimize cells re-renders through subscription
- Loading branch information
Showing
10 changed files
with
162 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,25 1,41 @@ | ||
import React from 'react'; | ||
import React, { memo } from 'react'; | ||
|
||
import { useGame } from '../hooks/useGame'; | ||
import { Cell } from './Cell'; | ||
import { useRerender } from '../hooks/useRerender'; | ||
import type { Position } from '../types/positioned'; | ||
import { GAME_EVENT } from '../constants/game'; | ||
import { Cell } from './Cell'; | ||
|
||
const RERENDER = [GAME_EVENT.MOVE]; | ||
|
||
const getStyle = ([x, y]: Position, size: number) => ({ | ||
'--cube-position-x': x, | ||
'--cube-position-y': y, | ||
'--map-size': size, | ||
}); | ||
|
||
export const Map = () => { | ||
const { map, cube } = useGame(); | ||
const MapCells = memo(function MapCells() { | ||
const { map } = useGame(); | ||
|
||
return ( | ||
<div className="map" style={getStyle(cube.position, map.size)}> | ||
<> | ||
{map.data.map((row) => | ||
row.map((cell) => { | ||
return <Cell key={cell.id} id={cell.id} />; | ||
}), | ||
)} | ||
</> | ||
); | ||
}); | ||
|
||
export const Map = () => { | ||
const { map, cube } = useGame(); | ||
|
||
useRerender(RERENDER); | ||
|
||
return ( | ||
<div className="map" style={getStyle(cube.position, map.size)}> | ||
<MapCells /> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,39 1,29 @@ | ||
import { useContext, useState, useEffect } from 'react'; | ||
import { useContext, useCallback } from 'react'; | ||
|
||
import { GameContext } from '../contexts/game'; | ||
import type { GameEvent } from '../types/game'; | ||
|
||
/** | ||
* Точка взаимодействия интерфейсов и игровым движком. | ||
* Производит ре-рендер компонента по месту вызова на каждое игровое событие. | ||
*/ | ||
export const useGame = () => { | ||
const game = useContext(GameContext); | ||
|
||
// Используется для ре-рендера компонента | ||
const [, setEvents] = useState<GameEvent[]>([]); | ||
|
||
useEffect(() => { | ||
if (!game) return; | ||
|
||
const unsubscribe = game.subscribeToEvents(({ event }) => { | ||
setEvents((prevEvents) => [...prevEvents, event]); | ||
}); | ||
|
||
return () => { | ||
unsubscribe(); | ||
}; | ||
}, []); | ||
|
||
if (game === null) { | ||
throw new Error('Hook useGame has been used outside of GameProvider'); | ||
throw new Error( | ||
'Хук useGame должен быть вызван в пределах компонента GameProvider', | ||
); | ||
} | ||
|
||
const getCell = useCallback( | ||
(id: string) => game.map.getCellById(id), | ||
[game.map], | ||
); | ||
|
||
return { | ||
game, | ||
map: game.map, | ||
cube: game.cube, | ||
fears: game.fears, | ||
getCell: (id: string) => game.map.getCellById(id), | ||
getCell, | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 1,71 @@ | ||
import { useState, useEffect } from 'react'; | ||
|
||
import type { GameEvent } from '../types/game'; | ||
import type { Game } from '../entities/Game'; | ||
import { useGame } from './useGame'; | ||
|
||
type RerenderCondition = | ||
| boolean | ||
| GameEvent[] | ||
| ((event: GameEvent, game: Game) => boolean | GameEvent[]); | ||
|
||
const getIsRerenderRestricted = (condition: RerenderCondition): boolean => { | ||
if (typeof condition === 'boolean') { | ||
return !condition; | ||
} | ||
|
||
if (Array.isArray(condition)) { | ||
return condition.length === 0; | ||
} | ||
|
||
return false; | ||
}; | ||
|
||
const getShouldRerender = ( | ||
game: Game, | ||
condition: RerenderCondition, | ||
event: GameEvent, | ||
): boolean => { | ||
if (getIsRerenderRestricted(condition)) { | ||
return false; | ||
} | ||
|
||
const _condition = | ||
typeof condition === 'function' ? condition(event, game) : condition; | ||
|
||
if (typeof _condition === 'boolean') { | ||
return _condition; | ||
} | ||
|
||
if (Array.isArray(_condition)) { | ||
return _condition.includes(event); | ||
} | ||
|
||
return false; | ||
}; | ||
|
||
/** | ||
* Производит ре-рендер компонента по месту вызова относительно переданного условия. | ||
*/ | ||
export const useRerender = (condition: RerenderCondition = false): void => { | ||
const { game } = useGame(); | ||
|
||
// Используется для ре-рендера компонента | ||
const [, setEventCount] = useState<number>(0); | ||
|
||
useEffect(() => { | ||
if (getIsRerenderRestricted(condition)) { | ||
return; | ||
} | ||
|
||
const unsubscribe = game.subscribeToEvents(({ event }) => { | ||
if (getShouldRerender(game, condition, event)) { | ||
setEventCount((count) => count 1); | ||
} | ||
}); | ||
|
||
return () => { | ||
unsubscribe(); | ||
}; | ||
}, [game, condition]); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters