Skip to content

Commit

Permalink
feat: add useRef
Browse files Browse the repository at this point in the history
  • Loading branch information
Caele committed Nov 4, 2024
1 parent f3e8aff commit 80c71d3
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 0 deletions.
54 changes: 54 additions & 0 deletions apis/supernova/src/__tests__/hooks.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
onContextMenu,
useEmbed,
useInteractionState,
useRef,
} from '../hooks';

describe('hooks', () => {
Expand Down Expand Up @@ -300,6 +301,59 @@ describe('hooks', () => {
});
});

describe('useRef', () => {
beforeEach(() => {
c = {};
initiate(c);
});
afterEach(() => {
teardown(c);
});
test('should initiate ref with value', () => {
let countValue;
c.fn = () => {
countValue = useRef(7);
};

run(c);
expect(countValue.current).toBe(7);
});
test('should refer to the same object', async () => {
let countValue;
let firstObject;
c.fn = () => {
countValue = useRef(7);
if (!firstObject) {
firstObject = countValue;
}
};

run(c);
expect(countValue.current).toBe(7);
countValue.current = 11;
run(c);
await frame();
expect(countValue.current).toBe(11);
expect(firstObject).toBe(countValue);
});
test('should not re-render when the ref changes', async () => {
let num = 0;
let countValue;
c.fn = () => {
countValue = useRef(7);
++num;
};

run(c);
expect(countValue.current).toBe(7);
countValue.current = 11;
expect(num).toBe(1);
await frame();
expect(num).toBe(1);
expect(countValue.current).toBe(11);
});
});

describe('useMemo', () => {
beforeEach(() => {
c = {};
Expand Down
25 changes: 25 additions & 0 deletions apis/supernova/src/hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,31 @@ export function useMemo(fn, deps) {
return h.value[1];
}

/**
* Creates a reference to a value not needed for rendering
*
* While Nebula does not have a virtual DOM, it is still useful
* to have a reference to an object that is retained across
* renders and in it self does not trigger a render.
* @entry
* @param {any} initialValue - The initial value.
* @example
* import { useRef } from '@nebula.js/stardust';
* // ...
* // initiate with simple value
* const timesRendered = useRef(0);
*
* useEffect(() => {
* render(layout);
* // increments the render counter, a useState would trigger another render
* timesRendered.current += 1;
* },[layout]);
*
*/
export function useRef(initialValue) {
return useMemo(() => ({ current: initialValue }), []);
}

/**
* Runs a callback function when a dependent changes.
*
Expand Down

0 comments on commit 80c71d3

Please sign in to comment.