Skip to content

Commit f600ab8

Browse files
committed
feat(hooks): add useRef hook
1 parent 36ad683 commit f600ab8

File tree

3 files changed

+74
-2
lines changed

3 files changed

+74
-2
lines changed

src/__tests__/useRef.test.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import Vue from 'vue';
2+
import { computed, onMounted } from 'vue-function-api';
3+
import useRef from '../useRef';
4+
import renderHook from '../util/renderHook';
5+
6+
describe('useRef', () => {
7+
it('should be defined', () => {
8+
expect(useRef).toBeDefined();
9+
});
10+
11+
it('should return element when passing ref name', () => {
12+
renderHook(() => {
13+
const app = useRef<HTMLDivElement>('app');
14+
const style = computed(() => (app.value ? app.value.style : undefined));
15+
16+
expect(app.value).toBeUndefined();
17+
expect(style.value).toBeUndefined();
18+
19+
onMounted(async () => {
20+
await Vue.nextTick();
21+
expect(app.value).toBeDefined();
22+
expect(style.value).toBeDefined();
23+
expect(style.value.width).toBe('1280px');
24+
expect(style.value.height).toBe('800px');
25+
});
26+
});
27+
});
28+
29+
it('should return element when passing function', () => {
30+
renderHook((_, { refs }) => {
31+
const nav = useRef<HTMLDivElement>(() => refs.nav);
32+
const style = computed(() => (nav.value ? nav.value.style : undefined));
33+
34+
expect(nav.value).toBeUndefined();
35+
expect(style.value).toBeUndefined();
36+
37+
onMounted(async () => {
38+
await Vue.nextTick();
39+
expect(nav.value).toBeDefined();
40+
expect(style.value).toBeDefined();
41+
expect(style.value.width).toBe('100%');
42+
});
43+
});
44+
});
45+
});

src/useRef.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import Vue from 'vue';
2+
import { value, onMounted } from 'vue-function-api';
3+
import { getRuntimeVM } from './util/runtime';
4+
5+
export type Ref = Vue | Element | Vue[] | Element[];
6+
7+
export default function useRef<T extends Ref>(target: string | (() => Ref)) {
8+
const ref = value<T>(undefined!);
9+
10+
onMounted(async () => {
11+
await Vue.nextTick();
12+
switch (typeof target) {
13+
case 'string':
14+
const { $refs } = getRuntimeVM(); // eslint-disable-line no-case-declarations
15+
ref.value = $refs[target] as T;
16+
break;
17+
case 'function':
18+
ref.value = target() as T;
19+
break;
20+
default:
21+
throw new TypeError('Target must be string or function.');
22+
}
23+
});
24+
25+
return ref;
26+
}

src/util/renderHook.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,9 @@ export default function renderHook<V, Props = unknown>(
2424
) {
2525
const App = createComponent({
2626
template: `
27-
<div id="app">
28-
<router-view></router-view>
27+
<div ref="app" id="app" :style="{ width: '1280px', height: '800px' }">
28+
<nav ref="nav" :style="{ width: '100%' }" />
29+
<router-view />
2930
</div>
3031
`,
3132

0 commit comments

Comments
 (0)