Skip to content

Commit

Permalink
🐛 react: fix useQuery reactivity
Browse files Browse the repository at this point in the history
  • Loading branch information
krispya committed Oct 24, 2024
1 parent 51db302 commit 9a88dcd
Showing 1 changed file with 27 additions and 24 deletions.
51 changes: 27 additions & 24 deletions packages/react/src/hooks/use-query.ts
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;
}

0 comments on commit 9a88dcd

Please sign in to comment.