Skip to content

Commit 6a05c52

Browse files
feat(hooks): add useRef
1 parent f322357 commit 6a05c52

File tree

10 files changed

+116
-21
lines changed

10 files changed

+116
-21
lines changed

README.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,44 @@ If you need nesting and relative positioning, use `Container`:
163163

164164
## Hooks
165165

166+
### `useRef`
167+
168+
Create a ref for your game object:
169+
170+
```ts
171+
import { useRef } from 'phaser-jsx';
172+
173+
function MyComponent() {
174+
const textRef = useRef<Phaser.GameObjects.Text>();
175+
// ...
176+
}
177+
```
178+
179+
Pass your ref to the JSX element:
180+
181+
```tsx
182+
// ...
183+
return <Text ref={textRef} onPointerDown={handleClick} />;
184+
```
185+
186+
Access your game object:
187+
188+
```ts
189+
function handleClick() {
190+
textRef.current?.text = 'Clicked';
191+
}
192+
```
193+
194+
Alternatively, you can get the game object with a callback ref:
195+
196+
```tsx
197+
<Text
198+
ref={(gameObject) => {
199+
gameObject.text = 'Hello, world!';
200+
}}
201+
/>
202+
```
203+
166204
### `useScene`
167205

168206
Retrieve the current Scene with the `useScene` hook:

src/hooks/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
export * from './useRef';
12
export * from './useScene';

src/hooks/useRef.test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { useRef } from './useRef';
2+
3+
it('defaults initial value to null', () => {
4+
expect(useRef()).toEqual({ current: null });
5+
});
6+
7+
it('creates ref with inital value', () => {
8+
expect(useRef(true)).toEqual({ current: true });
9+
});
10+
11+
it('sets ref current value', () => {
12+
const ref = useRef<string>();
13+
expect(ref).toEqual({ current: null });
14+
ref.current = 'value';
15+
expect(ref).toEqual({ current: 'value' });
16+
});

src/hooks/useRef.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import type { RefObject } from 'react';
2+
3+
/**
4+
* A hook that lets you reference a value that’s not needed for rendering.
5+
*
6+
* @param initialValue - The value you want the ref object’s current property to be initially. It can be a value of any type. This argument is ignored after the initial render.
7+
* @returns - Returns an object with a single property `current` (initially set to the `initialValue` you have passed).
8+
*/
9+
export function useRef<Type = null>(
10+
initialValue: Type | null = null,
11+
): RefObject<Type | null> {
12+
return {
13+
current: initialValue,
14+
};
15+
}

src/index.test.mjs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,18 @@ import {
1010
Image,
1111
jsx,
1212
render,
13+
useRef,
1314
useScene,
1415
Video,
1516
} from '../cjs/index.js';
1617

17-
[createElement, Image, render, Video, useScene].forEach((fun) => {
18-
it(`exports ${fun.name}`, () => {
19-
assert.strictEqual(typeof fun, 'function');
20-
});
21-
});
18+
[createElement, createRef, Image, render, Video, useRef, useScene].forEach(
19+
(fn) => {
20+
it(`exports ${fn.name}`, () => {
21+
assert.strictEqual(typeof fn, 'function');
22+
});
23+
},
24+
);
2225

2326
it('exports createElement', () => {
2427
assert.deepEqual(createElement(Image, { x: 42 }), {
@@ -28,8 +31,10 @@ it('exports createElement', () => {
2831
});
2932
});
3033

31-
it('exports createRef', () => {
32-
assert.deepEqual(createRef(), { current: null });
34+
[createRef, useRef].forEach((fn) => {
35+
it(`exports ${fn.name}`, () => {
36+
assert.deepEqual(fn(), { current: null });
37+
});
3338
});
3439

3540
it('exports jsx', () => {

src/index.test.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,27 @@
11
import {
22
Container,
33
createElement,
4+
createRef,
45
jsx,
56
Rectangle,
67
render,
78
Text,
9+
useRef,
810
useScene,
911
} from '.';
1012

11-
it.each([Container, Rectangle, Text, createElement, render, useScene])(
12-
'exports %p',
13-
(fun) => {
14-
expect(fun).toBeInstanceOf(Function);
15-
},
16-
);
13+
it.each([
14+
Container,
15+
Rectangle,
16+
Text,
17+
createElement,
18+
createRef,
19+
render,
20+
useRef,
21+
useScene,
22+
])('exports %p', (fn) => {
23+
expect(fn).toBeInstanceOf(Function);
24+
});
1725

1826
it('exports jsx', () => {
1927
expect(jsx).toBe(createElement);

src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
export * from './components';
22
export { createElement, jsx } from './element';
3-
export { useScene } from './hooks';
3+
export { useRef, useScene } from './hooks';
44
export { createRef } from './ref';
55
export { render } from './render';
66
export type { GameObjectProps, Ref } from './types';

src/ref/createRef.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
import type { Ref } from '../types';
1+
import type { RefObject } from 'react';
22

33
/**
44
* Creates a ref object which can contain arbitrary value.
55
*
6+
* @deprecated Use {@link useRef} instead.
7+
*
68
* @returns - Creates an object with a single property `current` (initially set to `null`).
79
*/
8-
export function createRef<Type>(): Ref<Type> {
10+
export function createRef<Type>(): RefObject<Type | null> {
911
return {
1012
current: null,
1113
};

src/render/ref.test.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type Phaser from 'phaser';
22

3-
import { createRef } from '..';
3+
import { createRef, useRef } from '..';
44
import { attachRef } from './ref';
55

66
const gameObject = {} as Phaser.GameObjects.GameObject;
@@ -20,6 +20,16 @@ it('attaches ref callback', () => {
2020

2121
it('attaches ref object', () => {
2222
const ref = createRef<Phaser.GameObjects.GameObject>();
23-
expect(attachRef(gameObject, ref));
23+
expect(
24+
attachRef(gameObject, ref as { current: Phaser.GameObjects.GameObject }),
25+
);
26+
expect(ref).toEqual({ current: gameObject });
27+
});
28+
29+
it('attaches ref', () => {
30+
const ref = useRef<Phaser.GameObjects.GameObject>();
31+
expect(
32+
attachRef(gameObject, ref as { current: Phaser.GameObjects.GameObject }),
33+
);
2434
expect(ref).toEqual({ current: gameObject });
2535
});

src/types/props.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import type { JSX } from 'react';
1+
import type { JSX, RefObject } from 'react';
22

3-
import type { Events, GameObject, RecursivePartial, Ref } from '.';
3+
import type { Events, GameObject, RecursivePartial } from '.';
44

55
type RefCallback<Type> = (gameObject: Type) => void;
66

77
interface ObjectProps<Type> extends Partial<Events> {
88
children?: JSX.Element | JSX.Element[] | null;
9-
ref?: RefCallback<Type> | Ref<Type>;
9+
ref?: RefCallback<Type> | RefObject<Type>;
1010
}
1111

1212
export type GameObjectProps<Type = GameObject> = ObjectProps<Type> &

0 commit comments

Comments
 (0)