Skip to content

Commit

Permalink
feat(hooks): add useRef hook
Browse files Browse the repository at this point in the history
  • Loading branch information
u3u committed Aug 6, 2019
1 parent 36ad683 commit f600ab8
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 2 deletions.
45 changes: 45 additions & 0 deletions src/__tests__/useRef.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import Vue from 'vue';
import { computed, onMounted } from 'vue-function-api';
import useRef from '../useRef';
import renderHook from '../util/renderHook';

describe('useRef', () => {
it('should be defined', () => {
expect(useRef).toBeDefined();
});

it('should return element when passing ref name', () => {
renderHook(() => {
const app = useRef<HTMLDivElement>('app');
const style = computed(() => (app.value ? app.value.style : undefined));

expect(app.value).toBeUndefined();
expect(style.value).toBeUndefined();

onMounted(async () => {
await Vue.nextTick();
expect(app.value).toBeDefined();
expect(style.value).toBeDefined();
expect(style.value.width).toBe('1280px');
expect(style.value.height).toBe('800px');
});
});
});

it('should return element when passing function', () => {
renderHook((_, { refs }) => {
const nav = useRef<HTMLDivElement>(() => refs.nav);
const style = computed(() => (nav.value ? nav.value.style : undefined));

expect(nav.value).toBeUndefined();
expect(style.value).toBeUndefined();

onMounted(async () => {
await Vue.nextTick();
expect(nav.value).toBeDefined();
expect(style.value).toBeDefined();
expect(style.value.width).toBe('100%');
});
});
});
});
26 changes: 26 additions & 0 deletions src/useRef.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import Vue from 'vue';
import { value, onMounted } from 'vue-function-api';
import { getRuntimeVM } from './util/runtime';

export type Ref = Vue | Element | Vue[] | Element[];

export default function useRef<T extends Ref>(target: string | (() => Ref)) {
const ref = value<T>(undefined!);

onMounted(async () => {
await Vue.nextTick();
switch (typeof target) {
case 'string':
const { $refs } = getRuntimeVM(); // eslint-disable-line no-case-declarations
ref.value = $refs[target] as T;
break;
case 'function':
ref.value = target() as T;
break;
default:
throw new TypeError('Target must be string or function.');
}
});

return ref;
}
5 changes: 3 additions & 2 deletions src/util/renderHook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ export default function renderHook<V, Props = unknown>(
) {
const App = createComponent({
template: `
<div id="app">
<router-view></router-view>
<div ref="app" id="app" :style="{ width: '1280px', height: '800px' }">
<nav ref="nav" :style="{ width: '100%' }" />
<router-view />
</div>
`,

Expand Down

0 comments on commit f600ab8

Please sign in to comment.