Skip to content

Commit 0341842

Browse files
iposokhinivan posokhin
andauthored
improvement: bind hooks' callbacks to a scope (#82)
* fix: function and variable declarations to be more correct * test: hooks calls in a scope * improvement: unify a way to declare type * improvement: bind hooks' callbacks to be fired in a scope --------- Co-authored-by: ivan posokhin <[email protected]>
1 parent e6bc134 commit 0341842

File tree

3 files changed

+67
-38
lines changed

3 files changed

+67
-38
lines changed

src/core/reflect.ts

Lines changed: 21 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,13 @@ export function reflectFactory(context: Context) {
2626
return function reflect<Props, Bind extends BindProps<Props> = BindProps<Props>>(
2727
config: ReflectConfig<Props, Bind>,
2828
): React.ExoticComponent<{}> {
29-
const { stores, events, data, functions } = sortProps(config);
29+
const { stores, events, data, functions } = sortProps(config.bind);
30+
const hooks = sortProps(config.hooks || {});
3031

3132
return React.forwardRef((props, ref) => {
3233
const storeProps = context.useUnit(stores, config.useUnitConfig);
3334
const eventsProps = context.useUnit(events as any, config.useUnitConfig);
34-
const functionProps = useBindedFunctions(functions);
35+
const functionProps = useBoundFunctions(functions);
3536

3637
const elementProps: Props = Object.assign(
3738
{ ref },
@@ -42,42 +43,38 @@ export function reflectFactory(context: Context) {
4243
props,
4344
);
4445

45-
const mounted = wrapToHook(
46-
config.hooks?.mounted,
47-
context,
48-
config.useUnitConfig,
49-
);
50-
const unmounted = wrapToHook(
51-
config.hooks?.unmounted,
52-
context,
53-
config.useUnitConfig,
54-
);
46+
const eventsHooks = context.useUnit(hooks.events as any, config.useUnitConfig);
47+
const functionsHooks = useBoundFunctions(hooks.functions);
5548

5649
React.useEffect(() => {
57-
if (mounted) mounted();
50+
const hooks: Hooks = Object.assign({}, functionsHooks, eventsHooks);
51+
52+
if (hooks.mounted) {
53+
hooks.mounted();
54+
}
5855

5956
return () => {
60-
if (unmounted) unmounted();
57+
if (hooks.unmounted) {
58+
hooks.unmounted();
59+
}
6160
};
62-
}, []);
61+
}, [eventsHooks, functionsHooks]);
6362

6463
return React.createElement(config.view as any, elementProps as any);
6564
});
6665
};
6766
}
6867

69-
function sortProps<Props, Bind extends BindProps<Props> = BindProps<Props>>(
70-
config: ReflectConfig<Props, Bind>,
71-
) {
68+
function sortProps<T extends object>(props: T) {
7269
type GenericEvent = Event<unknown> | Effect<unknown, unknown, unknown>;
7370

7471
const events: Record<string, GenericEvent> = {};
7572
const stores: Record<string, Store<unknown>> = {};
7673
const data: Record<string, unknown> = {};
7774
const functions: Record<string, Function> = {};
7875

79-
for (const key in config.bind) {
80-
const value = config.bind[key];
76+
for (const key in props) {
77+
const value = props[key];
8178

8279
if (is.event(value) || is.effect(value)) {
8380
events[key] = value;
@@ -93,30 +90,18 @@ function sortProps<Props, Bind extends BindProps<Props> = BindProps<Props>>(
9390
return { events, stores, data, functions };
9491
}
9592

96-
function useBindedFunctions(functions: Record<string, Function>) {
93+
function useBoundFunctions(functions: Record<string, Function>) {
9794
const scope = useProvidedScope();
9895

9996
return React.useMemo(() => {
100-
const bindedFunctions: Record<string, Function> = {};
97+
const boundFunctions: Record<string, Function> = {};
10198

10299
for (const key in functions) {
103100
const fn = functions[key];
104101

105-
bindedFunctions[key] = scopeBind(fn, { scope: scope || undefined, safe: true });
102+
boundFunctions[key] = scopeBind(fn, { scope: scope || undefined, safe: true });
106103
}
107104

108-
return bindedFunctions;
105+
return boundFunctions;
109106
}, [scope, functions]);
110107
}
111-
112-
function wrapToHook(hook: Hook | void, context: Context, config?: UseUnitConifg) {
113-
if (hookDefined(hook)) {
114-
return context.useUnit(hook as EventCallable<void>, config);
115-
}
116-
117-
return hook;
118-
}
119-
120-
function hookDefined(hook: Hook | void): hook is Hook {
121-
return Boolean(hook && (is.event(hook) || is.effect(hook)));
122-
}

src/core/types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ export type BindProps<Props> = {
2222

2323
export type Hook = (() => any) | EventCallable<void> | Effect<void, any, any>;
2424

25-
export interface Hooks {
25+
export type Hooks = {
2626
mounted?: Hook;
2727
unmounted?: Hook;
28-
}
28+
};
2929

3030
export type UseUnitConifg = Parameters<typeof useUnit>[1];

src/no-ssr/reflect.test.tsx

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,28 @@ describe('hooks', () => {
317317
expect(mounted.mock.calls.length).toBe(1);
318318
});
319319

320+
test('callback in scope', () => {
321+
const mounted = createEvent();
322+
const $isMounted = createStore(false).on(mounted, () => true);
323+
324+
const scope = fork();
325+
326+
const Name = reflect({
327+
view: InputBase,
328+
bind: {},
329+
hooks: { mounted: () => mounted() },
330+
});
331+
332+
render(
333+
<Provider value={scope}>
334+
<Name data-testid="name" />
335+
</Provider>,
336+
);
337+
338+
expect($isMounted.getState()).toBe(false);
339+
expect(scope.getState($isMounted)).toBe(true);
340+
});
341+
320342
test('event', () => {
321343
const changeName = createEvent<string>();
322344
const $name = restore(changeName, '');
@@ -339,6 +361,28 @@ describe('hooks', () => {
339361

340362
expect(fn.mock.calls.length).toBe(1);
341363
});
364+
365+
test('event in scope', () => {
366+
const mounted = createEvent();
367+
const $isMounted = createStore(false).on(mounted, () => true);
368+
369+
const scope = fork();
370+
371+
const Name = reflect({
372+
view: InputBase,
373+
bind: {},
374+
hooks: { mounted },
375+
});
376+
377+
render(
378+
<Provider value={scope}>
379+
<Name data-testid="name" />
380+
</Provider>,
381+
);
382+
383+
expect($isMounted.getState()).toBe(false);
384+
expect(scope.getState($isMounted)).toBe(true);
385+
});
342386
});
343387

344388
describe('unmounted', () => {

0 commit comments

Comments
 (0)