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

Commit 52d1042

Browse files
committed
resolves #84
resolves #105
1 parent e3e89e0 commit 52d1042

File tree

18 files changed

+335
-61
lines changed

18 files changed

+335
-61
lines changed

README.md

Lines changed: 54 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ with deeply nested objects, a
9797
* [removeCallback](#removecallback)
9898
* [resetGlobal](#resetglobal)
9999
* [setGlobal](#setglobal)
100+
* [WithGlobal](#withglobal)
101+
* [withInit](#withinit)
100102
* [Frequently Asked Questions](https://github.com/CharlesStover/reactn/blob/master/FAQ.md)
101103
* [Support](#support)
102104

@@ -123,7 +125,7 @@ attempt to render.
123125
It is recommended that you initialize the global state just prior to mounting
124126
with `ReactDOM`.
125127

126-
```JavaScript
128+
```javascript
127129
import React, { setGlobal } from 'reactn';
128130
import ReactDOM from 'react-dom';
129131
import App from './App';
@@ -156,7 +158,7 @@ functions.
156158
In order to tell TypeScript the shape of your global state when you are not using
157159
a Provider, create a file at `src/global.d.ts` with the following contents:
158160

159-
```JavaScript
161+
```javascript
160162
import 'reactn';
161163

162164
declare module 'reactn/default' {
@@ -223,7 +225,7 @@ directly into the React namespace. As a result, `Component` and `PureComponent`
223225
will have access to the `global` and `dispatch` member variables and
224226
`setGlobal` method.
225227

226-
```JavaScript
228+
```javascript
227229
import React from 'reactn'; // <-- reactn
228230
import Card from '../card/card';
229231

@@ -273,7 +275,7 @@ By importing React and ReactN separately, the React namespace remains
273275
unchanged. You can inject ReactN's global functionality into your vanilla React
274276
component by using the `@reactn` decorator imported from the `reactn` package.
275277

276-
```JavaScript
278+
```javascript
277279
import React from 'react';
278280
import reactn from 'reactn'; // <-- reactn
279281
import Card from '../card/card';
@@ -324,7 +326,7 @@ export default class Cards extends React.PureComponent {
324326
Using [React Hooks](https://reactjs.org/docs/hooks-intro.html), you can harness
325327
`useGlobal` to access the global state.
326328

327-
```JavaScript
329+
```javascript
328330
import React, { useGlobal } from 'reactn'; // <-- reactn
329331
import Card from '../card/card';
330332

@@ -354,7 +356,7 @@ export default Cards;
354356
You may also use the `useDispatch` hook analogously to the `useReducer` hook by
355357
providing a function to `useDispatch`.
356358

357-
```JavaScript
359+
```javascript
358360
import React, { useDispatch } from 'reactn'; // <-- reactn
359361

360362
const incrementReducer = (global, dispatch, action) => ({
@@ -385,7 +387,7 @@ By providing a second parameter to `useDispatch` that is the key of the global
385387
state, the return value of that reducer will set that property of the global
386388
state. This allows you to write your reducers similar to React's `useReducer`.
387389

388-
```JavaScript
390+
```javascript
389391
import React, { useDispatch } from 'reactn'; // <-- reactn
390392

391393
const incrementReducer = (count, action) =>
@@ -422,7 +424,7 @@ new global state will trigger the very same callback.
422424

423425
The only parameter is the callback function.
424426

425-
```JavaScript
427+
```javascript
426428
import { addCallback, setGlobal } from 'reactn';
427429

428430
// Every time the global state changes, this function will execute.
@@ -446,7 +448,7 @@ setGlobal({ value: 1 });
446448
The return value of `addCallback` is a function that, when executed, removes
447449
the callback.
448450

449-
```JavaScript
451+
```javascript
450452
import { addCallback, setGlobal } from 'reactn';
451453

452454
const removeAlert = addCallback(global => {
@@ -479,7 +481,7 @@ when dispatching. The reducer function that you _use_ when dispatching does not
479481
contain the global state or map of reducers. Those are prefixed for you
480482
automatically.
481483

482-
```JavaScript
484+
```javascript
483485
import { addReducer, setGlobal, useDispatch, useGlobal } from 'reactn';
484486

485487
// Initialize the global state with the value 0.
@@ -523,7 +525,7 @@ For a class component, the analogous method is
523525
The `dispatch` parameter on a reducer allows you to write "sagas," or a single
524526
reducer that dispatches other reducers.
525527

526-
```JavaScript
528+
```javascript
527529
// add(1)
528530
addReducer('add', (global, dispatch, i) => ({
529531
x: global.x + i,
@@ -555,7 +557,7 @@ should use `useDispatch` or `this.dispatch`.
555557

556558
`getDispatch` has no parameters.
557559

558-
```JavaScript
560+
```javascript
559561
import { getDispatch } from 'reactn';
560562

561563
// Access this.dispatch.reducerName outside of a Component.
@@ -577,7 +579,7 @@ nothing more than return a current snapshot of the global state.
577579

578580
`getGlobal` has no parameters.
579581

580-
```JavaScript
582+
```javascript
581583
import { getGlobal } from 'reactn';
582584

583585
// Access this.global.value outside of a Component.
@@ -596,7 +598,7 @@ the return value of `addCallback`.
596598

597599
The only parameter is the callback function itself.
598600

599-
```JavaScript
601+
```javascript
600602
import { addCallback, removeCallback, setGlobal } from 'reactn';
601603

602604
function alertCallback(global) {
@@ -624,7 +626,7 @@ including callbacks, property listeners, and reducers.
624626

625627
There are no parameters.
626628

627-
```JavaScript
629+
```javascript
628630
import { getGlobal, resetGlobal, setGlobal } from 'reactn';
629631

630632
// Set the value.
@@ -652,7 +654,7 @@ The optional second parameter is a callback.
652654

653655
`setGlobal` with a new global state:
654656

655-
```JavaScript
657+
```javascript
656658
import { setGlobal } from 'reactn';
657659

658660
// Set loading to true.
@@ -663,7 +665,7 @@ setGlobal({
663665

664666
`setGlobal` with a new global state and a callback:
665667

666-
```JavaScript
668+
```javascript
667669
import { setGlobal } from 'reactn';
668670

669671
// Set loading to true.
@@ -690,7 +692,7 @@ The first parameter is a function for getting global state values.
690692
The second parameter is a function for setting global state values (similar to
691693
`dispatch`).
692694

693-
```JavaScript
695+
```javascript
694696
import React, { withGlobal } from 'reactn';
695697

696698
// A button that displays the value and, when clicked, increments it.
@@ -727,7 +729,41 @@ export default withGlobal(
727729
}
728730
})
729731
)(MyComponent);
732+
```
733+
734+
##### withInit
735+
736+
In some cases (such as when using Next.js), you may be unable to run a setup
737+
script prior to your ReactN components mounting. In order to instantiate your
738+
global state and reducers prior to mounting, you may use the `withInit` Higher
739+
Order Component. This HOC will await the setting of your global state before
740+
mounting the provided Lower Order Component (e.g. `<App />`).
741+
742+
```javascript
743+
import React, { useDispatch, useGlobal, withInit } from 'reactn';
744+
745+
const INITIAL_REDUCERS = {
746+
addOne: ({ count }) => ({
747+
count: count + 1,
748+
}),
749+
};
750+
751+
const INITIAL_STATE = {
752+
count: 0,
753+
};
730754

755+
export default withInit(
756+
INITIAL_STATE,
757+
INITIAL_REDUCERS,
758+
)(function App() {
759+
const addOne = useDispatch('addOne');
760+
const [ count ] = useGlobal('count');
761+
return (
762+
<button onClick={addOne}>
763+
Count: {count}
764+
</button>
765+
);
766+
});
731767
```
732768

733769
## Support

docs/src/reactn.ts

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
1-
import { addReducers, setGlobal } from 'reactn';
2-
import { Dispatch, State } from 'reactn/default';
1+
import { addReducer, setGlobal } from 'reactn';
2+
import { State } from 'reactn/default';
33

44
const INITIAL_STATE: State = {
55
color: '#61DAFB',
66
};
77

88
setGlobal(INITIAL_STATE);
99

10-
addReducers({
11-
12-
setColor: (global: State, _dispatch: Dispatch, color: string) => {
13-
if (color !== global.color) {
14-
return { color };
15-
}
16-
},
17-
10+
addReducer('setColor', (global, _dispatch, color) => {
11+
if (color !== global.color) {
12+
return { color };
13+
}
1814
});

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.1.4",
3+
"version": "2.1.5",
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/add-reducer.ts

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { State } from '../default';
2-
import Reducer from '../types/reducer';
1+
import { State, Reducers } from '../default';
2+
import Reducer, { AdditionalReducers } from '../types/reducer';
33
import GlobalStateManager from './global-state-manager';
44

55

@@ -8,10 +8,34 @@ type BooleanFunction = () => boolean;
88

99

1010

11-
export default function _addReducer<G extends {} = State>(
12-
globalStateManager: GlobalStateManager<G>,
11+
export default function _addReducer<
12+
G extends {} = State,
13+
R extends {} = Reducers,
14+
ReducerName extends keyof R = keyof R,
15+
>(
16+
globalStateManager: GlobalStateManager<G, R>,
17+
name: ReducerName,
18+
reducer: R[ReducerName],
19+
);
20+
export default function _addReducer<
21+
G extends {} = State,
22+
R extends {} = Reducers,
23+
>(
24+
globalStateManager: GlobalStateManager<G, R>,
1325
name: string,
14-
reducer: Reducer<G>,
26+
reducer: Reducer<G, R & AdditionalReducers<G, R>>,
27+
);
28+
export default function _addReducer<
29+
G extends {} = State,
30+
R extends {} = Reducers,
31+
ReducerName extends keyof R = keyof R,
32+
>(
33+
globalStateManager: GlobalStateManager<G, R>,
34+
name: ReducerName | string,
35+
reducer: R[ReducerName] | Reducer<G, R & AdditionalReducers<G, R>>,
1536
): BooleanFunction {
16-
return globalStateManager.addReducer(name, reducer);
37+
return globalStateManager.addReducer(
38+
name as string,
39+
reducer as Reducer<G, R>,
40+
);
1741
};

src/add-reducers.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@ type BooleanFunction = () => boolean;
1212
export default function _addReducers<
1313
G extends {} = State,
1414
R extends {} = Reducers,
15+
AR extends AdditionalReducers<G, R> = AdditionalReducers<G, R>,
16+
ARR extends AdditionalReducers<G, R & AR> = AdditionalReducers<G, R & AR>,
1517
>(
1618
globalStateManager: GlobalStateManager<G, R>,
17-
reducers: AdditionalReducers<G, R & any>,
19+
reducers: Partial<R> & ARR,
1820
): BooleanFunction {
1921

2022
// Amalgamate all the functions to remove these reducers.

src/index.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import ReactNProvider from '../types/provider';
1212
import Reducer, { AdditionalReducers } from '../types/reducer';
1313
import { GlobalTuple, StateTuple } from '../types/use-global';
1414
import WithGlobal, { Getter, Setter } from '../types/with-global';
15+
import WithInit from '../types/with-init';
1516
import { ReactNComponent, ReactNPureComponent } from './components';
1617
import addCallback from './add-callback';
1718
import addReducer from './add-reducer';
@@ -27,6 +28,7 @@ import setGlobal from './set-global';
2728
import useDispatch from './use-dispatch';
2829
import useGlobal from './use-global';
2930
import withGlobal from './with-global';
31+
import withInit from './with-init';
3032
import React = require('react');
3133

3234

@@ -43,13 +45,17 @@ interface ReactN extends Omit<typeof React, 'Component' | 'default' | 'PureCompo
4345
callback: Callback<G>,
4446
): BooleanFunction;
4547

46-
addReducer<G extends {} = State>(
48+
addReducer<G extends {} = State, R extends {} = Reducers, ReducerName extends keyof R = keyof R>(
49+
name: ReducerName,
50+
reducer: R[ReducerName],
51+
): BooleanFunction;
52+
addReducer<G extends {} = State, R extends {} = Reducers>(
4753
name: string,
48-
reducer: Reducer<G>,
54+
reducer: Reducer<G, R & AdditionalReducers<G, R>>,
4955
): BooleanFunction;
5056

51-
addReducers<G extends {} = State, R extends {} = Reducers>(
52-
reducers: AdditionalReducers<G, R>,
57+
addReducers<G extends {} = State, R extends {} = Reducers, AR extends AdditionalReducers<G, R> = AdditionalReducers<G, R>, ARR extends AdditionalReducers<G, R & AR> = AdditionalReducers<G, R & AR>>(
58+
reducers: Partial<R> & ARR,
5359
): BooleanFunction;
5460

5561
// This line should not need to exist, since `Component` exists on both the
@@ -106,6 +112,11 @@ interface ReactN extends Omit<typeof React, 'Component' | 'default' | 'PureCompo
106112
getter?: Getter<G, R, HP, LP>,
107113
setter?: Setter<G, R, HP, LP>,
108114
): WithGlobal<HP, LP>;
115+
116+
withInit<G extends {} = State, R extends {} = Reducers, P extends {} = {}>(
117+
initialGlobal?: NewGlobalState<G> | null,
118+
initialReducers?: null | R,
119+
): WithInit<P, G, R>;
109120
}
110121

111122
declare namespace ReactNTypes {
@@ -166,4 +177,5 @@ export = Object.assign(reactn, React, {
166177
useDispatch: useDispatch.bind(null, null),
167178
useGlobal: useGlobal.bind(null, null),
168179
withGlobal: withGlobal.bind(null, null),
180+
withInit,
169181
}) as ReactN & typeof ReactNTypes;

0 commit comments

Comments
 (0)