Skip to content

Commit 6bf00c7

Browse files
committed
refactor: extract module support into separate Modulizer class
1 parent e69c284 commit 6bf00c7

File tree

6 files changed

+235
-79
lines changed

6 files changed

+235
-79
lines changed

example/index.js

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import xs from 'xstream';
22
import {createElement} from 'react';
33
import {render} from 'react-dom';
4-
import {setModules} from '../src/Incorporator'
4+
import {setModules} from '../src/Modulizer'
55
import {h, makeComponent} from '../src/index';
66

77
function main(sources) {
@@ -23,17 +23,17 @@ function main(sources) {
2323
const getRef = el => {
2424
el.foo='bar';
2525
}
26-
const vdom$ = count$.map(i =>
27-
h('div', [
26+
const vdom$ = count$.map(i => {
27+
return h('div', [
2828
h('h1', {ref: getRef}, `Hello ${i} times`),
2929
h('button', {
3030
sel: btnSel,
3131
className: 'clicker',
3232
domProps: {foo: 3},
3333
domClass: {hello: true, goodbye: false}
34-
}, 'Reset'),
35-
]),
36-
);
34+
}, 'Reset')
35+
])
36+
});
3737

3838
return {
3939
react: vdom$,

src/Incorporator.ts

+8-68
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {PureComponent, createElement, createRef} from 'react';
1+
import {PureComponent, createElement} from 'react';
22
import {Scope} from './scope';
33

44
type Props = {
@@ -12,76 +12,20 @@ type State = {
1212
flip: boolean;
1313
};
1414

15-
let moduleEntries: any = []
16-
17-
let onMounts: any[] = []
18-
let onUpdates: any[] = []
19-
let onUnmounts: any[] = []
20-
21-
export function setModules(mods: any) {
22-
if (mods === null || typeof mods !== 'object') return;
23-
moduleEntries = Object.entries(mods)
24-
onMounts = moduleEntries.map(mod => [mod[0], mod[1].componentDidMount]).filter(mod => mod[1])
25-
onUpdates = moduleEntries.map(mod => [mod[0], mod[1].componentDidUpdate]).filter(mod => mod[1])
26-
onUnmounts = moduleEntries.map(mod => [mod[0], mod[1].componentWillUnmount]).filter(mod => mod[1])
27-
}
28-
29-
export function hasModuleProps (props) {
30-
return props
31-
? moduleEntries.some(([mkey]) => props.hasOwnProperty(mkey))
32-
: false
33-
}
34-
35-
function moduleProcessor (base, current, props) {
36-
if (current && base.length) {
37-
base.forEach(([key, f]) => {
38-
const prop = props[key]
39-
if (prop) f(current, prop)
40-
});
41-
}
42-
}
43-
4415
export default class Incorporator extends PureComponent<Props, State> {
45-
private ref: any;
46-
private selector: string | symbol;
47-
private unsubscribe: any;
48-
private element: any;
49-
private setRef: any;
50-
5116
constructor(props: Props) {
5217
super(props);
53-
this.element = null
54-
5518
this.state = {flip: false};
5619
this.selector = props.targetProps.sel;
57-
58-
const useRef = hasModuleProps(props.targetProps)
59-
if (props.targetRef) {
60-
if (typeof props.targetRef === 'function' && useRef) {
61-
this.setRef = element => {
62-
this.element = element;
63-
props.targetRef(element);
64-
};
65-
66-
this.ref = this.setRef;
67-
} else {
68-
this.ref = props.targetRef;
69-
}
70-
} else {
71-
this.ref = useRef ? createRef() : null;
72-
}
7320
}
7421

22+
private selector: string | symbol;
23+
private unsubscribe: any;
24+
7525
public componentDidMount() {
7626
this.unsubscribe = this.props.scope.subscribe(this.selector, () => {
7727
this.setState((prev: any) => ({flip: !prev.flip}));
7828
});
79-
80-
moduleProcessor(onMounts, this.element || (this.ref && this.ref.current), this.props.targetProps)
81-
}
82-
83-
public componentDidUpdate() {
84-
moduleProcessor(onUpdates, this.element || (this.ref && this.ref.current), this.props.targetProps)
8529
}
8630

8731
private incorporateHandlers<P>(props: P, scope: Scope): P {
@@ -102,31 +46,27 @@ export default class Incorporator extends PureComponent<Props, State> {
10246
}
10347

10448
private materializeTargetProps() {
105-
const {targetProps, scope} = this.props;
49+
const {targetProps, targetRef, scope} = this.props;
10650
let output = {...targetProps};
10751
output = this.incorporateHandlers(output, scope);
108-
if (this.ref) {
109-
output.ref = this.ref;
52+
if (targetRef) {
53+
output.ref = targetRef;
11054
}
11155
delete output.sel;
112-
moduleEntries.forEach(pair => delete output[pair[0]])
11356
return output;
11457
}
11558

11659
public render() {
11760
const {target} = this.props;
11861
const targetProps = this.materializeTargetProps();
119-
12062
if (targetProps.children) {
12163
return createElement(target, targetProps, targetProps.children);
12264
} else {
12365
return createElement(target, targetProps);
12466
}
12567
}
12668

127-
public componentWillUnmount() {
128-
moduleProcessor(onUnmounts, this.element || (this.ref && this.ref.current), this.props.targetProps)
129-
69+
public componentWillUnmount() {
13070
this.unsubscribe();
13171
}
13272
}

src/Modulizer.ts

+214
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
import {Component, ComponentType, forwardRef, createRef, createElement} from 'react';
2+
import Incorporator from './Incorporator'
3+
4+
let moduleEntries: any = []
5+
6+
let onMounts: any[] = []
7+
let onUpdates: any[] = []
8+
let onUnmounts: any[] = []
9+
10+
export function setModules(mods: any) {
11+
if (mods === null || typeof mods !== 'object') return;
12+
moduleEntries = Object.entries(mods)
13+
onMounts = moduleEntries.map(mod => [mod[0], mod[1].componentDidMount]).filter(mod => mod[1])
14+
onUpdates = moduleEntries.map(mod => [mod[0], mod[1].componentDidUpdate]).filter(mod => mod[1])
15+
onUnmounts = moduleEntries.map(mod => [mod[0], mod[1].componentWillUnmount]).filter(mod => mod[1])
16+
}
17+
18+
export function usesModules() {
19+
return moduleEntries.length > 0
20+
}
21+
22+
export function hasModuleProps (props) {
23+
return props
24+
? moduleEntries.some(([mkey]) => props.hasOwnProperty(mkey))
25+
: false
26+
}
27+
28+
function moduleProcessor (base, current, props) {
29+
if (current && base.length) {
30+
base.forEach(([key, f]) => {
31+
const prop = props[key]
32+
if (prop) f(current, prop)
33+
});
34+
}
35+
}
36+
37+
export class Modulizer extends Component<any, any> {
38+
private ref: any;
39+
private element: any;
40+
private setRef: any;
41+
constructor(props) {
42+
super(props);
43+
this.element = null
44+
45+
const {targetProps, targetRef} = props
46+
const useRef = hasModuleProps(targetProps)
47+
if (targetRef) {
48+
if (typeof targetRef === 'function' && useRef) {
49+
this.setRef = element => {
50+
this.element = element;
51+
targetRef(element);
52+
};
53+
54+
this.ref = this.setRef;
55+
} else {
56+
this.ref = targetRef;
57+
}
58+
} else {
59+
this.ref = useRef ? createRef() : null;
60+
}
61+
}
62+
63+
public componentDidMount() {
64+
moduleProcessor(onMounts, this.element || (this.ref && this.ref.current), this.props.targetProps)
65+
}
66+
67+
public componentDidUpdate() {
68+
moduleProcessor(onUpdates, this.element || (this.ref && this.ref.current), this.props.targetProps)
69+
}
70+
71+
public componentWillUnmount() {
72+
moduleProcessor(onUnmounts, this.element || (this.ref && this.ref.current), this.props.targetProps)
73+
}
74+
75+
render() {
76+
const targetProps = {...this.props.targetProps}
77+
moduleEntries.forEach(pair => delete targetProps[pair[0]])
78+
const output: any = {...this.props, targetRef: this.ref, targetProps};
79+
80+
return createElement(Incorporator, output);
81+
}
82+
}
83+
84+
// export function Modulizer(Comp: any): ComponentType<any> {
85+
// class ModulizerComponent extends Component<any, any> {
86+
// private ref: any;
87+
// private element: any;
88+
// private setRef: any;
89+
// constructor(props) {
90+
// super(props);
91+
// this.element = null
92+
93+
// const {targetProps, targetRef} = props.modularizerProps
94+
// const useRef = hasModuleProps(targetProps)
95+
// if (targetRef) {
96+
// if (typeof targetRef === 'function' && useRef) {
97+
// this.setRef = element => {
98+
// this.element = element;
99+
// targetRef(element);
100+
// };
101+
102+
// this.ref = this.setRef;
103+
// } else {
104+
// this.ref = targetRef;
105+
// }
106+
// } else {
107+
// this.ref = useRef ? createRef() : null;
108+
// }
109+
// }
110+
111+
// public componentDidMount() {
112+
// moduleProcessor(onMounts, this.element || (this.ref && this.ref.current), this.props.modularizerProps.targetProps)
113+
// }
114+
115+
// public componentDidUpdate() {
116+
// moduleProcessor(onUpdates, this.element || (this.ref && this.ref.current), this.props.modularizerProps.targetProps)
117+
// }
118+
119+
// public componentWillUnmount() {
120+
// moduleProcessor(onUnmounts, this.element || (this.ref && this.ref.current), this.props.modularizerProps.targetProps)
121+
// }
122+
123+
// render() {
124+
// const targetProps = {...this.props.modularizerProps.targetProps}
125+
// moduleEntries.forEach(pair => delete targetProps[pair[0]])
126+
// const output: any = {...this.props.modularizerProps, targetRef: this.ref, targetProps};
127+
128+
// return createElement(Comp, output);
129+
// }
130+
// }
131+
132+
// return forwardRef<any, any>((props, ref) => {
133+
// return createElement(ModulizerComponent, {modularizerProps: props, targetRef: ref} )
134+
// });
135+
// }
136+
137+
// export default class Modulizer extends PureComponent<Props, State> {
138+
// private ref: any;
139+
// private element: any;
140+
// private setRef: any;
141+
142+
// constructor(props: Props) {
143+
// super(props);
144+
// this.element = null
145+
146+
// const useRef = hasModuleProps(props.targetProps)
147+
// if (props.targetRef) {
148+
// if (typeof props.targetRef === 'function' && useRef) {
149+
// this.setRef = element => {
150+
// this.element = element;
151+
// props.targetRef(element);
152+
// };
153+
154+
// this.ref = this.setRef;
155+
// } else {
156+
// this.ref = props.targetRef;
157+
// }
158+
// } else {
159+
// this.ref = useRef ? createRef() : null;
160+
// }
161+
// }
162+
163+
// public componentDidMount() {
164+
// this.unsubscribe = this.props.scope.subscribe(this.selector, () => {
165+
// this.setState((prev: any) => ({flip: !prev.flip}));
166+
// });
167+
168+
// moduleProcessor(onMounts, this.element || (this.ref && this.ref.current), this.props.targetProps)
169+
// }
170+
171+
// public componentDidUpdate() {
172+
// moduleProcessor(onUpdates, this.element || (this.ref && this.ref.current), this.props.targetProps)
173+
// }
174+
175+
// public componentWillUnmount() {
176+
// moduleProcessor(onUnmounts, this.element || (this.ref && this.ref.current), this.props.targetProps)
177+
178+
// this.unsubscribe();
179+
// }
180+
181+
// private incorporateHandlers<P>(props: P, scope: Scope): P {
182+
// const handlers = scope.getSelectorHandlers(this.selector);
183+
// for (const evType of Object.keys(handlers)) {
184+
// const onFoo = `on${evType[0].toUpperCase()}${evType.slice(1)}`;
185+
// props[onFoo] = (ev: any) => handlers[evType]._n(ev);
186+
// }
187+
// return props;
188+
// }
189+
190+
// private materializeTargetProps() {
191+
// const {targetProps, scope} = this.props;
192+
// let output = {...targetProps};
193+
// output = this.incorporateHandlers(output, scope);
194+
// if (this.ref) {
195+
// output.ref = this.ref;
196+
// }
197+
// delete output.sel;
198+
// moduleEntries.forEach(pair => delete output[pair[0]])
199+
// return output;
200+
// }
201+
202+
// public render() {
203+
// const {target} = this.props;
204+
// const targetProps = this.materializeTargetProps();
205+
206+
// if (targetProps.children) {
207+
// return createElement(target, targetProps, targetProps.children);
208+
// } else {
209+
// return createElement(target, targetProps);
210+
// }
211+
// }
212+
213+
214+
// }

src/h.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
Attributes,
88
} from 'react';
99
import {incorporate} from './incorporate';
10-
import { hasModuleProps } from './Incorporator';
10+
import {hasModuleProps} from './Modulizer';
1111

1212
export type PropsExtensions = {
1313
sel?: string | symbol;

0 commit comments

Comments
 (0)