-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
27 additions
and
24 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,40 +1,43 @@ | ||
import { QueryParameter, QueryResult } from '@koota/core'; | ||
import { useEffect, useState } from 'react'; | ||
import { Entity, QueryParameter } from '@koota/core'; | ||
import { useEffect, useMemo, useReducer } from 'react'; | ||
import { useWorld } from '../world/use-world'; | ||
|
||
export function useQuery<T extends QueryParameter[]>(...parameters: T): QueryResult<T> { | ||
export function useQuery<T extends QueryParameter[]>(...parameters: T) { | ||
const memoizedParameters = useMemo(() => parameters, [parameters]); | ||
const world = useWorld(); | ||
const [entities, setEntities] = useState<QueryResult<T>>(world.query(...parameters)); | ||
const entities = useMemo(() => world.query(...memoizedParameters), [world, memoizedParameters]); | ||
const [, forceUpdate] = useReducer((v) => v + 1, 0); | ||
|
||
// Set entities at effect time | ||
useEffect(() => { | ||
const unsubAdd = world.onAdd(parameters, (entity) => { | ||
setEntities((v) => { | ||
// @ts-expect-error - QueryResult is a readonly array, but we need to mutate it | ||
v.push(entity); | ||
return v; | ||
}); | ||
}); | ||
const mutableEntities = entities as unknown as Entity[]; | ||
mutableEntities.length = 0; | ||
mutableEntities.push(...world.query(...memoizedParameters)); | ||
|
||
forceUpdate(); | ||
}, [world]); | ||
|
||
const unsubRemove = world.onRemove(parameters, (entity) => { | ||
setEntities((v) => { | ||
// Remove the entity from the array by moving and popping it | ||
const index = v.indexOf(entity); | ||
// Move the last element to the index of the removed element | ||
// @ts-expect-error - QueryResult is a readonly array, but we need to mutate it | ||
v[index] = v[v.length - 1]; | ||
// Pop the last element | ||
// @ts-expect-error - QueryResult is a readonly array, but we need to mutate it | ||
v.pop(); | ||
// Subscribe to changes | ||
useEffect(() => { | ||
const unsubAdd = world.onAdd(memoizedParameters, (entity) => { | ||
const mutableEntities = entities as unknown as Entity[]; | ||
mutableEntities.push(entity); | ||
forceUpdate(); | ||
}); | ||
|
||
return v; | ||
}); | ||
const unsubRemove = world.onRemove(memoizedParameters, (entity) => { | ||
const mutableEntities = entities as unknown as Entity[]; | ||
const index = mutableEntities.indexOf(entity); | ||
mutableEntities[index] = mutableEntities[mutableEntities.length - 1]; | ||
mutableEntities.pop(); | ||
forceUpdate(); | ||
}); | ||
|
||
return () => { | ||
unsubAdd(); | ||
unsubRemove(); | ||
}; | ||
}, [world, parameters]); | ||
}, [world]); | ||
|
||
return entities; | ||
} |