Skip to content

Commit

Permalink
Merge pull request #89 from atellmer/development
Browse files Browse the repository at this point in the history
Bugfixes
  • Loading branch information
atellmer authored Aug 29, 2024
2 parents 1f66d77 + 560ee48 commit 1cf8099
Show file tree
Hide file tree
Showing 14 changed files with 249 additions and 52 deletions.
2 changes: 1 addition & 1 deletion examples/.gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/dev
/dev-ssr
/dev-native
/dev-server
/dev-desktop
15 changes: 14 additions & 1 deletion packages/core/src/scope/scope.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Callback, ElementKey, AppResources, AppResource } from '../shared';
import type { Callback, CallbackWithValue, ElementKey, AppResources, AppResource } from '../shared';
import { platform, detectIsServer } from '../platform';
import { EventEmitter } from '../emitter';
import { type Fiber, Awaiter } from '../fiber';
Expand Down Expand Up @@ -36,6 +36,7 @@ class Scope {
private isDynamic = platform.detectIsDynamic();
private isServer = detectIsServer();
private emitter = new EventEmitter();
private afterEvent: CallbackWithValue<unknown> = null;

private resetActions() {
this.actions = {};
Expand Down Expand Up @@ -385,6 +386,7 @@ class Scope {
this.setIsHydrateZone(false);
this.setIsUpdateZone(false);
this.resetActions();
this.setAfterEvent(null);
}

getEmitter() {
Expand Down Expand Up @@ -423,6 +425,17 @@ class Scope {
this.resources = new Map();
this.isServer && (this.resourceId = 0);
}

setAfterEvent(fn: CallbackWithValue<unknown>) {
this.afterEvent = fn;
}

runAfterEvent(x: unknown) {
const fn = this.afterEvent;

this.afterEvent = null;
fn && platform.raf(() => fn(x));
}
}

type Actions = Record<
Expand Down
79 changes: 50 additions & 29 deletions packages/core/src/use-state/use-state.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { render } from '@dark-engine/platform-browser';
import { createBrowserEnv, dom, setInputValue, sleep } from '@test-utils';
import { type SyntheticEvent } from '@dark-engine/platform-browser';

import { dom } from '@test-utils';
import { component } from '../component/component';
import { component } from '../component';
import { useState } from './use-state';
import { type MutableRef, useRef } from '../ref';

let host: HTMLElement = null;
let { render, host } = createBrowserEnv();

beforeEach(() => {
host = document.createElement('div');
({ render, host } = createBrowserEnv());
});

describe('@core/use-state', () => {
Expand All @@ -23,7 +24,7 @@ describe('@core/use-state', () => {
return <div>{count}</div>;
});

render(App(), host);
render(<App />);
expect(host.innerHTML).toBe(content(0));

setCount(count + 1);
Expand All @@ -50,7 +51,7 @@ describe('@core/use-state', () => {
return [<div>text</div>, <div>{count}</div>];
});

render(App(), host);
render(<App />);
expect(host.innerHTML).toBe(content(0));

setCount(count + 1);
Expand Down Expand Up @@ -90,10 +91,6 @@ describe('@core/use-state', () => {
count: 0,
}));

const $render = (props = {}) => {
render(App(props), host);
};

let setCountsOne = [];
let setCountsTwo = [];

Expand Down Expand Up @@ -133,7 +130,7 @@ describe('@core/use-state', () => {
items[items.length - 2] = temp;
};

$render();
render(<App />);
expect(host.innerHTML).toBe(content(items));

setCountsOne[1](1);
Expand All @@ -147,13 +144,13 @@ describe('@core/use-state', () => {
setCountsOne = [];
setCountsTwo = [];
swap();
$render();
render(<App />);
expect(host.innerHTML).toBe(content(items));

setCountsOne = [];
setCountsTwo = [];
swap();
$render();
render(<App />);
expect(host.innerHTML).toBe(content(items));
});

Expand Down Expand Up @@ -184,10 +181,6 @@ describe('@core/use-state', () => {
count: 0,
}));

const $render = (props = {}) => {
render(App(props), host);
};

let setCounts: Array<(value: number) => void> = [];

const Item = component<ItemProps>(({ id }) => {
Expand All @@ -213,7 +206,7 @@ describe('@core/use-state', () => {
items[items.length - 2] = temp;
};

$render();
render(<App />);
expect(host.innerHTML).toBe(content(items));

setCounts[1](1);
Expand All @@ -222,7 +215,7 @@ describe('@core/use-state', () => {
items[items.length - 2].count = 2;
swap();
setCounts = [];
$render();
render(<App />);
expect(host.innerHTML).toBe(content(items));

setCounts[1](20);
Expand All @@ -231,7 +224,7 @@ describe('@core/use-state', () => {
items[items.length - 2].count = 30;
swap();
setCounts = [];
$render();
render(<App />);
expect(host.innerHTML).toBe(content(items));
});

Expand Down Expand Up @@ -268,10 +261,6 @@ describe('@core/use-state', () => {
count: 0,
}));

const $render = (props = {}) => {
render(App(props), host);
};

let setCounts: Array<(value: number) => void> = [];

const Item = component<ItemProps>(({ id }) => {
Expand Down Expand Up @@ -307,7 +296,7 @@ describe('@core/use-state', () => {
items[items.length - 2] = temp;
};

$render();
render(<App />);
expect(host.innerHTML).toBe(content(items));

setCounts[1](1);
Expand All @@ -316,7 +305,7 @@ describe('@core/use-state', () => {
items[items.length - 2].count = 2;
swap();
setCounts = [];
$render();
render(<App />);
expect(host.innerHTML).toBe(content(items));

setCounts[1](20);
Expand All @@ -325,7 +314,7 @@ describe('@core/use-state', () => {
items[items.length - 2].count = 30;
swap();
setCounts = [];
$render();
render(<App />);
expect(host.innerHTML).toBe(content(items));
});

Expand All @@ -348,7 +337,7 @@ describe('@core/use-state', () => {
return [<div>1</div>, <div>2</div>, <div>3</div>];
});

render(App(), host);
render(<App />);
expect(host.innerHTML).toBe(content(false));

setFlag(true);
Expand All @@ -357,4 +346,36 @@ describe('@core/use-state', () => {
setFlag(false);
expect(host.innerHTML).toBe(content(false));
});

test('forces direct update for input value', async () => {
// https://github.com/atellmer/dark/issues/82
let inputRef: MutableRef<HTMLInputElement> = null;
const App = component(() => {
inputRef = useRef<HTMLInputElement>(null);
const [value, setValue] = useState('0');
const handleSetValue = (e: SyntheticEvent<InputEvent, HTMLInputElement>) => {
const value = e.target.value;
const $value = value.replace(/\D/g, '');

setValue($value);
};

return <input ref={inputRef} value={value} onInput={handleSetValue} />;
});

render(<App />);
const input = inputRef.current;

setInputValue(input, '0rrrr');
await sleep(20);
expect(input.value).toBe('0');

setInputValue(input, '0abc');
await sleep(20);
expect(input.value).toBe('0');

setInputValue(input, '123abc');
await sleep(20);
expect(input.value).toBe('123');
});
});
9 changes: 8 additions & 1 deletion packages/core/src/use-state/use-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,14 @@ function useState<T = unknown>(initialValue: T | (() => T)): [T, (value: Value<T
get: () => scope.value,
set: (x: T) => (scope.value = x),
reset: (x: T) => (scope.value = x),
shouldUpdate: (p: T, n: T) => !detectIsEqual(p, n),
shouldUpdate: (p: T, n: T) => {
const $scope = $$scope();
const should = !detectIsEqual(p, n);

!should && $scope.runAfterEvent(n);

return should;
},
});

update(tools);
Expand Down
42 changes: 42 additions & 0 deletions packages/data/src/use-query/use-query.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -248,4 +248,46 @@ describe('@data/use-query', () => {
setMarker('b');
expect(body.innerHTML).toBe(content('b', 10, 20, true));
});

test('uses previous results from cache correctly', async () => {
const spy = jest.fn();
const App = component<{ id: number }>(({ id }) => {
const { isFetching, data, error } = useQuery(Key.GET_DATA, ({ id }) => api.getData(id), {
strategy: 'state-only',
variables: { id },
extractId: x => x.id,
});

spy([isFetching, data, error]);

return null;
});

render(withProvider(<App id={1} />));
expect(spy).toHaveBeenCalledWith([true, null, null]);
await waitQuery();
expect(spy).toHaveBeenCalledWith([false, 10, null]);
spy.mockClear();

render(withProvider(<App id={2} />));
spy.mockClear();
await waitUntilEffectsStart();
expect(spy).toHaveBeenCalledWith([true, 10, null]);
spy.mockClear();
await waitQuery();
expect(spy).toHaveBeenCalledWith([false, 20, null]);
spy.mockClear();

render(withProvider(<App id={1} />));
spy.mockClear();
await waitUntilEffectsStart();
expect(spy).toHaveBeenCalledWith([false, 10, null]);
spy.mockClear();

render(withProvider(<App id={2} />));
spy.mockClear();
await waitUntilEffectsStart();
expect(spy).toHaveBeenCalledWith([false, 20, null]);
spy.mockClear();
});
});
13 changes: 10 additions & 3 deletions packages/data/src/use-query/use-query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ function useQuery<T, V extends Variables>(key: string, query: Query<T, V>, optio
const initiator = useId();
const record = cache.read<T>(key, { id: cacheId });
const pending = getPending<T>(cache, key, cacheId);
const hasPending = Boolean(pending);
const isSuspenseOnly = strategy === 'suspense-only';
const isHybrid = strategy === 'hybrid';
const isStateOnly = strategy === 'state-only';
Expand Down Expand Up @@ -193,10 +194,16 @@ function useQuery<T, V extends Variables>(key: string, query: Query<T, V>, optio
}

useEffect(() => {
const shouldSkip = isHydration || lazy || pending || state.isFetching || record?.valid;
const shouldSkip = isHydration || lazy || hasPending || state.isFetching || record?.valid;

if (shouldSkip) return;
refetch();
if (shouldSkip) {
if (record?.valid && state.data !== record.data && !detectIsPromise(record.data)) {
state.data = record.data;
update();
}
} else {
refetch();
}
}, [...mapRecord(variables)]);

useEffect(() => {
Expand Down
1 change: 1 addition & 0 deletions packages/platform-browser/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ export const AS_ATTR = '_as';
export const DANGER_HTML_ATTR = '__danger';
export const EXCLUDE_ATTR_MARK = '$';
export const DASH_MARK = '-';
export const PREVENT = '__prevent';
7 changes: 7 additions & 0 deletions packages/platform-browser/src/dom/dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import {
EXCLUDE_ATTR_MARK,
DANGER_HTML_ATTR,
DASH_MARK,
PREVENT,
} from '../constants';
import type {
NativeElement,
Expand Down Expand Up @@ -163,6 +164,11 @@ function performAttribute(
return null;
}

if (attrName === PREVENT) {
tagElement[PREVENT] = true;
return null;
}

if (attrName === AS_ATTR) {
attrName = attrName.slice(1, AS_ATTR.length);
}
Expand Down Expand Up @@ -282,6 +288,7 @@ function commitCreation(fiber: Fiber<NativeElement>) {
}

detectIsTagVirtualNode(fiber.inst) && addAttributes(fiber.element, fiber.inst, isHydration);
fiber.element.parentElement?.[PREVENT] && (fiber.element[PREVENT] = true);
}

function commitUpdate(fiber: Fiber<NativeElement>) {
Expand Down
Loading

0 comments on commit 1cf8099

Please sign in to comment.