Skip to content
This repository was archived by the owner on Feb 14, 2023. It is now read-only.

Commit ab6b746

Browse files
committed
resolves #78
resolves #66
1 parent 8cbede4 commit ab6b746

File tree

10 files changed

+244
-118
lines changed

10 files changed

+244
-118
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "reactn",
3-
"version": "2.0.3",
3+
"version": "2.0.4",
44
"author": "Charles Stover <[email protected]>",
55
"description": "React, but with built-in global state management.",
66
"homepage": "https://github.com/CharlesStover/reactn#readme",

src/create-provider.tsx

Lines changed: 10 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -4,58 +4,24 @@ import Callback from '../types/callback';
44
import Dispatcher, { ExtractArguments } from '../types/dispatcher';
55
import Dispatchers from '../types/dispatchers';
66
import NewGlobalState from '../types/new-global-state';
7+
import ReactNProvider from '../types/provider';
78
import Reducer, { AdditionalReducers } from '../types/reducer';
9+
import UseGlobal, { GlobalTuple, StateTuple } from '../types/use-global';
10+
import WithGlobal, { Getter, Setter } from '../types/with-global';
811
import Context from './context';
912
import addReducer from './add-reducer';
1013
import addReducers from './add-reducers';
1114
import GlobalStateManager from './global-state-manager';
1215
import setGlobal from './set-global';
1316
import useDispatch, { UseDispatch } from './use-dispatch';
14-
import useGlobal, { GlobalTuple, StateTuple, UseGlobal } from './use-global';
17+
import useGlobal from './use-global';
1518
import REACT_CONTEXT_ERROR from './utils/react-context-error';
16-
import withGlobal, { Getter, Setter, WithGlobal } from './with-global';
19+
import withGlobal from './with-global';
1720

1821

1922

2023
type BooleanFunction = () => boolean;
2124

22-
export interface ReactNProvider<
23-
G extends {} = State,
24-
R extends {} = Reducers,
25-
> {
26-
addCallback(callback: Callback<G>): BooleanFunction;
27-
addReducer<A extends any[] = any[]>(
28-
name: string,
29-
reducer: Reducer<G, R, A>,
30-
): BooleanFunction;
31-
addReducers(reducers: AdditionalReducers<G, R>): BooleanFunction;
32-
dispatch: Dispatchers<G, R>;
33-
getDispatch(): Dispatchers<G, R>;
34-
getGlobal(): G;
35-
global: G;
36-
removeCallback(callback: Callback<G>): boolean;
37-
reset(): void;
38-
setGlobal(
39-
newGlobalState: NewGlobalState<G>,
40-
callback?: Callback<G>,
41-
): Promise<G>;
42-
useDispatch<A extends any[] = any[]>(
43-
reducer: Reducer<G, R, A>,
44-
): Dispatcher<G, A>;
45-
useDispatch<K extends keyof R = keyof R>(
46-
reducer: K,
47-
): Dispatcher<G, ExtractArguments<R[K]>>;
48-
useGlobal(): GlobalTuple<G>;
49-
useGlobal<Property extends keyof G>(
50-
property: Property,
51-
): StateTuple<G, Property>;
52-
withGlobal<HP, LP>(
53-
getter: Getter<G, HP, LP>,
54-
setter: Setter<G, HP, LP>,
55-
): WithGlobal<HP, LP>;
56-
new (props: {}, context?: any): React.Component<{}, {}>;
57-
}
58-
5925

6026

6127
export default function _createProvider<
@@ -156,11 +122,11 @@ export default function _createProvider<
156122
return useGlobal(globalStateManager, property);
157123
}
158124

159-
public static withGlobal<HP, LP>(
160-
getter: Getter<G, HP, LP> = (globalState: G): G => globalState,
161-
setter: Setter<G, HP, LP> = (): null => null,
125+
public static withGlobal<HP extends {} = {}, LP extends {} = {}>(
126+
getter: Getter<G, R, HP, LP> = (global: G): G => global,
127+
setter: Setter<G, R, HP, LP> = (): null => null,
162128
): WithGlobal<HP, LP> {
163-
return withGlobal<G, HP, LP>(globalStateManager, getter, setter);
129+
return withGlobal<G, R, HP, LP>(globalStateManager, getter, setter);
164130
}
165131

166132
public render(): JSX.Element {
@@ -170,5 +136,5 @@ export default function _createProvider<
170136
</Context.Provider>
171137
);
172138
}
173-
}
139+
};
174140
}

src/index.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,15 @@ import {
88
import Dispatcher, { ExtractArguments } from '../types/dispatcher';
99
import Dispatchers from '../types/dispatchers';
1010
import NewGlobalState from '../types/new-global-state';
11+
import ReactNProvider from '../types/provider';
1112
import Reducer, { AdditionalReducers } from '../types/reducer';
13+
import { GlobalTuple, StateTuple } from '../types/use-global';
14+
import WithGlobal, { Getter, Setter } from '../types/with-global';
1215
import { ReactNComponent, ReactNPureComponent } from './components';
1316
import addCallback from './add-callback';
1417
import addReducer from './add-reducer';
1518
import addReducers from './add-reducers';
16-
import createProvider, { ReactNProvider } from './create-provider';
19+
import createProvider from './create-provider';
1720
import reactn from './decorator';
1821
import defaultGlobalStateManager from './default-global-state-manager';
1922
import getDispatch from './get-dispatch';
@@ -22,8 +25,8 @@ import removeCallback from './remove-callback';
2225
import resetGlobal from './reset-global';
2326
import setGlobal from './set-global';
2427
import useDispatch from './use-dispatch';
25-
import useGlobal, { GlobalTuple, StateTuple } from './use-global';
26-
import withGlobal, { Getter, Setter, WithGlobal } from './with-global';
28+
import useGlobal from './use-global';
29+
import withGlobal from './with-global';
2730

2831

2932

@@ -92,9 +95,9 @@ interface ReactN extends TypeOfReact {
9295

9396
useGlobal<G extends {} = State>(): GlobalTuple<G>;
9497

95-
withGlobal<G extends {} = State, HP extends {} = {}, LP extends {} = {}>(
96-
getter?: Getter<G, HP, LP>,
97-
setter?: Setter<G, HP, LP>,
98+
withGlobal<G extends {} = State, R extends {} = Reducers, HP extends {} = {}, LP extends {} = {}>(
99+
getter?: Getter<G, R, HP, LP>,
100+
setter?: Setter<G, R, HP, LP>,
98101
): WithGlobal<HP, LP>;
99102
}
100103

src/use-global.ts

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import useForceUpdate from 'use-force-update';
33
import { State } from '../default';
44
import Callback from '../types/callback';
55
import NewGlobalState from '../types/new-global-state';
6+
import UseGlobal, { GlobalTuple, StateTuple } from '../types/use-global';
67
import Context from './context';
78
import defaultGlobalStateManager from './default-global-state-manager';
89
import GlobalStateManager from './global-state-manager';
@@ -11,30 +12,10 @@ import REACT_HOOKS_ERROR from './utils/react-hooks-error';
1112

1213

1314

14-
export type GlobalTuple<GS> = [
15-
GS,
16-
(newGlobalState: NewGlobalState<GS>, callback?: Callback<GS>) => Promise<GS>,
17-
];
18-
19-
type Setter<G extends {}, P extends keyof G> =
20-
(newValue: G[P], callback?: Callback<G>) => Promise<G>;
21-
22-
export type StateTuple<G extends {}, P extends keyof G> = [
23-
G[P],
24-
Setter<G, P>,
25-
];
26-
27-
export type UseGlobal<G extends {}, Property extends keyof G> =
28-
GlobalTuple<G> | StateTuple<G, Property>;
29-
3015
type VoidFunction = () => void;
3116

3217

3318

34-
35-
36-
37-
3819
// useGlobal()
3920
export default function _useGlobal<G extends {} = State>(
4021
overrideGlobalStateManager: GlobalStateManager<G> | null,
Lines changed: 37 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
import {
2-
ComponentClass,
3-
Context,
4-
createElement,
5-
FunctionComponent,
6-
} from 'react';
7-
import { State } from '../default';
1+
import * as React from 'react';
2+
import { Reducers, State } from '../default';
83
import Callback from '../types/callback';
94
import { ReactNComponentClass } from '../types/component-class';
5+
import Dispatchers from '../types/dispatchers';
6+
import WithGlobal, {
7+
Getter,
8+
LowerOrderComponent,
9+
Setter,
10+
} from '../types/with-global';
1011
import NewGlobalState from '../types/new-global-state';
1112
import { ReactNComponent } from './components';
1213
import ReactNContext from './context';
@@ -16,25 +17,6 @@ import { ReactNGlobal, ReactNSetGlobal } from './methods';
1617

1718

1819

19-
export type Getter<G extends {}, HP, LP> = (globalState: G, props: HP) =>
20-
null | Partial<LP> | void;
21-
22-
type LowerOrderComponent<P = {}> =
23-
ComponentClass<P> | FunctionComponent<P> | string;
24-
25-
type SetGlobal<G extends {} = State> = (
26-
newGlobalState: NewGlobalState<G>,
27-
callback?: Callback<G>,
28-
) => Promise<G>;
29-
30-
export type Setter<G, HP, LP> = (setGlobal: SetGlobal<G>, props: HP) =>
31-
null | Partial<LP> | void;
32-
33-
export type WithGlobal<HP, LP> =
34-
(Component: LowerOrderComponent<LP>) => ComponentClass<HP>;
35-
36-
37-
3820
// Get the name of a Component.
3921
const componentName = <
4022
P extends {} = {},
@@ -66,12 +48,13 @@ hoc(MyComponent);
6648
*/
6749
export default function _withGlobal<
6850
G extends {} = State,
51+
R extends {} = Reducers,
6952
HP extends {} = {},
7053
LP extends {} = {},
7154
>(
72-
globalStateManager: GlobalStateManager<G> | null = null,
73-
getter: Getter<G, HP, LP> = (globalState: G): G => globalState,
74-
setter: Setter<G, HP, LP> = (): null => null,
55+
globalStateManager: GlobalStateManager<G, R> | null = null,
56+
getter: Getter<G, R, HP, LP> = (global: G): G => global,
57+
setter: Setter<G, R, HP, LP> = (): null => null,
7558
): WithGlobal<HP, LP> {
7659
return function ReactNWithGlobal(
7760
Component: LowerOrderComponent<LP>,
@@ -83,18 +66,31 @@ export default function _withGlobal<
8366

8467
return class ReactNHOC extends ReactNComponent<HP, {}, G> {
8568

86-
// Context knows it provides a GlobalStateManager,
87-
// but not the shape <GS> of the GlobalState that it holds.
88-
public static contextType: Context<GlobalStateManager<G>> =
89-
ReactNContext as Context<GlobalStateManager<G>>;
69+
// Context knows it provides a GlobalStateManager, but not the shape.
70+
public static contextType: React.Context<GlobalStateManager<G, R>> =
71+
ReactNContext;
9072

9173
public static displayName = `${componentName(Component)}-ReactN`;
9274

75+
// Context knows it provides a GlobalStateManager, but not the shape.
76+
public context: GlobalStateManager<G, R>;
77+
78+
public get dispatch(): Dispatchers<G, R> {
79+
return this.globalStateManager.dispatchers;
80+
}
81+
9382
public get global(): G {
94-
return ReactNGlobal<G>(
95-
this,
96-
globalStateManager || this.context || defaultGlobalStateManager
97-
);
83+
return ReactNGlobal<G>(this, this.globalStateManager);
84+
}
85+
86+
public get globalStateManager(): GlobalStateManager<G, R> {
87+
if (globalStateManager) {
88+
return globalStateManager;
89+
}
90+
if (this.context instanceof GlobalStateManager) {
91+
return this.context;
92+
}
93+
return defaultGlobalStateManager as GlobalStateManager<G, R>;
9894
}
9995

10096
public setGlobal = (
@@ -106,20 +102,18 @@ export default function _withGlobal<
106102
!isComponentDidMount &&
107103
!isComponentDidUpdate &&
108104
!isSetGlobalCallback,
109-
globalStateManager ||
110-
this.context ||
111-
defaultGlobalStateManager,
105+
this.globalStateManager,
112106
);
113107

114108
public render(): JSX.Element {
115109

116110
// @ts-ignore: LP doesn't match HP
117111
const lowerOrderProps: LP = {
118112
...this.props,
119-
...getter(this.global, this.props),
120-
...setter(this.setGlobal, this.props),
113+
...getter(this.global, this.dispatch, this.props),
114+
...setter(this.setGlobal, this.dispatch, this.props),
121115
};
122-
return createElement(Component, lowerOrderProps);
116+
return <Component {...lowerOrderProps} />;
123117
}
124118
};
125119
};

tests/with-global.test.ts

Lines changed: 0 additions & 4 deletions
This file was deleted.

tests/with-global.test.tsx

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import * as React from 'react';
2+
import { render } from 'react-testing-library';
3+
import ReactN = require('../src/index');
4+
import ReactNProvider from '../types/provider';
5+
import { Getter } from '../types/with-global';
6+
import { G, INITIAL_STATE } from './utils/initial';
7+
8+
9+
10+
// TS2339: Property 'innerHTML' does not exist on type 'HTMLSpanElement'.
11+
interface Container extends HTMLSpanElement {
12+
innerHTML: string;
13+
}
14+
15+
interface Props {
16+
z: string;
17+
}
18+
19+
20+
21+
const INNER_HTML: string = `<span>${INITIAL_STATE.z}</span>`;
22+
23+
const mapGlobalToProps: Getter<G, {}, {}, Props> = ({ z }: G): Props => ({ z });
24+
25+
const TestComponent = ({ z }: Props): JSX.Element => {
26+
return <span>{z}</span>;
27+
};
28+
29+
30+
31+
describe('withGlobal', (): void => {
32+
33+
afterEach((): void => {
34+
ReactN.resetGlobal();
35+
});
36+
37+
it('should support default global state', async (): Promise<void> => {
38+
await ReactN.setGlobal(INITIAL_STATE);
39+
const TestComponentHoc: React.ComponentClass<{}> =
40+
ReactN.withGlobal(mapGlobalToProps)(TestComponent);
41+
42+
const testComponent = render(<TestComponentHoc />);
43+
44+
const span: Container = testComponent.container as Container;
45+
expect(span.innerHTML).toBe(INNER_HTML);
46+
});
47+
48+
describe('Provider', (): void => {
49+
50+
let Provider: ReactNProvider<G>;
51+
beforeEach((): void => {
52+
Provider = ReactN.createProvider(INITIAL_STATE);
53+
});
54+
55+
it('should support Context', (): void => {
56+
const TestComponentHoc: React.ComponentClass<{}> =
57+
ReactN.withGlobal(mapGlobalToProps)(TestComponent);
58+
59+
const testComponent = render(
60+
<Provider>
61+
<TestComponentHoc />
62+
</Provider>,
63+
);
64+
65+
const span: Container = testComponent.container as Container;
66+
expect(span.innerHTML).toBe(INNER_HTML);
67+
});
68+
69+
it('should support Provider', (): void => {
70+
const TestComponentHoc: React.ComponentClass<{}> =
71+
Provider.withGlobal(mapGlobalToProps)(TestComponent);
72+
73+
const testComponent = render(<TestComponentHoc />);
74+
75+
const span: Container = testComponent.container as Container;
76+
expect(span.innerHTML).toBe(INNER_HTML);
77+
});
78+
79+
});
80+
81+
});

0 commit comments

Comments
 (0)