-
Notifications
You must be signed in to change notification settings - Fork 80
/
share.tsx
73 lines (68 loc) · 2.53 KB
/
share.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
/**
* Copyright 2018 Shift Devices AG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Component, ComponentFactory, h, JSX, RenderableProps } from 'preact';
import { getDisplayName } from '../utils/component';
import { ObjectButNotFunction } from '../utils/types';
import { Store } from './store';
/**
* Shares a store with its state among all instances of the wrapped component.
*
* @param store - The store whose state is shared among all instances of the wrapped component.
* @return A function that returns the higher-order component that shares the state of the store as props.
*
* Example:
* ```
* interface SharedProps {
* value: number;
* }
*
* const store = new Store<SharedProps>({ value: 1 });
*
* function incrementValue() {
* store.setState({ value: store.state.value + 1});
* }
*
* class Counter extends Component<SharedProps> {
* public render({ value }: RenderableProps<SharedProps>): JSX.Element {
* return <div onClick={incrementValue}>Value: { value }</div>;
* }
* }
*
* const HOC = share(store)(Counter);
*
* export { HOC as Counter };
* ```
*/
export function share<SharedProps extends ObjectButNotFunction, ProvidedProps extends ObjectButNotFunction = {}>(
store: Store<SharedProps>,
) {
return function decorator(
WrappedComponent: ComponentFactory<SharedProps & ProvidedProps>,
) {
return class Share extends Component<ProvidedProps & Partial<SharedProps>> {
public static displayName = `Share(${getDisplayName(WrappedComponent)})`;
public componentDidMount(): void {
store.subscribe(this);
}
public componentWillUnmount(): void {
store.unsubscribe(this);
}
public render(props: RenderableProps<ProvidedProps & Partial<SharedProps>>): JSX.Element {
return <WrappedComponent {...store.state} {...props as any} />; // This order allows the parent component to override the shared store with properties.
}
};
};
}