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

Commit

Permalink
resolves #60
Browse files Browse the repository at this point in the history
  • Loading branch information
quisido committed Jul 21, 2019
1 parent 379a968 commit 9821b9f
Show file tree
Hide file tree
Showing 53 changed files with 1,123 additions and 378 deletions.
12 changes: 7 additions & 5 deletions Provider.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Provider

_Requires React >= 16.3.0_

ReactN's global components attempt to receive the global state from a React
Context. If the ReactN Context cannot be found, then the global components will
fallback to a default global state.
Expand Down Expand Up @@ -84,15 +86,15 @@ Provider.resetGlobal();

Provider.setGlobal({ x: 1 });

Provider.useDispatch();
Provider.useDispatch(); // Requires React >= 16.8.0

Provider.useDispatch('name');
Provider.useDispatch('name'); // Requires React >= 16.8.0

Provider.useDispatch(reducerFunction);
Provider.useDispatch(reducerFunction); // Requires React >= 16.8.0

Provider.useGlobal();
Provider.useGlobal(); // Requires React >= 16.8.0

Provider.useGlobal('property');
Provider.useGlobal('property'); // Requires React >= 16.8.0
```

## useGlobal and withGlobal
Expand Down
276 changes: 276 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,11 @@ with deeply nested objects, a
* [removeCallback](#removecallback)
* [resetGlobal](#resetglobal)
* [setGlobal](#setglobal)
* [useDispatch](#usedispatch)
* [useGlobal](#useglobal)
* [withGlobal](#withglobal)
* [withInit](#withinit)
* [Terminology](#terminology)
* [Frequently Asked Questions](https://github.com/CharlesStover/reactn/blob/master/FAQ.md)
* [Support](#support)

Expand Down Expand Up @@ -681,6 +684,152 @@ setGlobal(
);
```

##### useDispatch

_Requires React >= 16.8.0_

The `useDispatch` helper function is a React Hook analogous to the `useReducer`
hook built into React itself. `useDispatch` will dispatch a global reducer that
has been added to ReactN via the [`addReducer`](#addreducer),
[`addReducers`](#addreducers), or [`withInit`](#withinit) helper functions or a
global reducer that you specify inline as a parameter.

###### useDispatch()

`useDispatch()` with no parameters will return a map of all of your global
reducers.

```javascript
import { useDispatch } from 'reactn';

function MyComponent() {
const dispatch = useDispatch();
dispatch.add(1);
dispatch.substract(2);
return null;
}
```

###### useDispatch(Function)

`useDispatch(f)` allows you to define your global reducer inline. This method
is particularly useful if you prefer to import your reducers as needed or keep
your singleton reducers with the components that use them.

```javascript
import React, { useDispatch, useGlobal } from 'reactn';

function MyComponent() {
const [ count ] = useGlobal('count');
const add = useDispatch(
(global, _dispatch, n) => ({
count: global.count + n,
}),
);
return (
<button onClick={() => add(1)}>
{count}.
</span>
);
}
```

###### useDispatch(Function, keyof State)

`useDispatch(f, 'property')` allows you to define your global property reducer
inline. A property reducer changes only one property of the global state, which
can greatly simplify your reducer logic.

```javascript
import React, { useDispatch, useGlobal } from 'reactn';

function MyComponent() {
const [ count ] = useGlobal('count');
const add = useDispatch(
(count, n) => count + n,
'count',
);
return (
<button onClick={() => add(1)}>
{count}.
</span>
);
}
```

###### useDispatch(keyof Reducers)

`useDispatch('reducerName')` allows you to dispatch a global reducer.

```javascript
import React, { useDispatch, useGlobal } from 'reactn';

function MyComponent() {
const [ count ] = useGlobal('count');
const add = useDispatch('add');
return (
<button onClick={() => add(1)}>
{count}.
</span>
);
}
```

##### useGlobal

_Requires React >= 16.8.0_

`useGlobal` is a React Hook analogous to the `useState` Hook built into React
itself. `useGlobal` returns the global state or parts thereof.

###### useGlobal()

`useGlobal()` with no parameters will return the entire global state object and
a function for changing properties of the global state.

The `setGlobal` function returned by `useGlobal` is analogous to the
[`setGlobal`](#setglobal) helper function and `this.setGlobal` class method.

```javascript
import React, { useGlobal } from 'reactn';

function MyComponent() {
const [ global, setGlobal ] = useGlobal();
const generateNumber = () => {
setGlobal(g => ({
generations: g.generations + 1,
myNumber: Math.floor(Math.random() * 100),
});
};
return (
<button onClick={generateNumber}>
#{global.generations}: {global.myNumber}
</button>
);
}
```
###### useGlobal(keyof State)
`useGlobal('property')` returns a specific global state property and a function
for updating that property.
```javascript
import React, { useGlobal } from 'reactn';

const getRandomNumber = () =>
Math.floor(Math.random() * 100);

function MyComponent() {
const [ myNumber, setMyNumber ] = useGlobal('myNumber');
return (
<button onClick={() => setMyNumber(getRandomNumber())}>
{myNumber}
</button>
)
}
```
##### withGlobal
Use `withGlobal` to return a higher-order component to convert global state
Expand Down Expand Up @@ -766,6 +915,133 @@ export default withInit(
});
```
## Terminology
ReactN strictly maintains accurate terminology for its data structures. The
majority of ReactN's data structures are meant to be black box to simplify the
user experience, only referenced by name in the package's code. They are
outlined here for transparency and to ease community contributions.
### Dispatcher
When you pass a reducer to ReactN via [`addReducer`](#addreducer),
[`addReducers`](#addreducers), [`useDispatch`](#usedispatch), or
[`withInit`](#withinit), ReactN returns a dispatcher.
A dispatcher is a function that wraps a reducer, passing the global state and
global reducers as parameters tying its return value to the global state.
Dispatchers and reducers have a 1-to-1 relationship and are tightly bound to
each other.
In documentation, dispatchers are often referred to as reducers to decrease the
cognitive overhead and conceptually strengthen their 1-to-1 relationship.
For example, an "add" reducer may be defined as follows:
```javascript
function add(global, _dispatch, n) {
return { count: global.count + n };
}
```
When you call this reducer, you only need to call `add(1)`. This difference in
call signature is because you are calling the _dispatcher_.
A dispatcher, in pseudo-code, conceptually looks as follows:
```javascript
function dispatchAdd(n) {
const { dispatchers, set, state } = globalStateManager;
const newGlobalState = add(state, dispatchers, n);
return set(newGlobalState);
}
```
### Global State Manager
The global state manager is the core object that powers ReactN. It maintains
the state, global dispatchers, and subscriptions.
#### Default Global State Manager
The default global state manager is the global state manager used by all of
ReactN _unless otherwise specified_. To specify a different global state
manager, you must use a
[Provider](https://github.com/CharlesStover/reactn/blob/master/Provider.md).
ReactN Components and Hooks will attempt to find a global state manager via
the Context. If one does not exist via Context, it will fallback to the default
global state manager.
### Reducer
A reducer is a function that accepts the current global state, a map of all
global reducers, and any number of additional parameters. A reducer returns a
change to the global state. It does not need to return the entire new global
state. It only needs to return key-value pairs of changed properties.
An example "add" reducer may be defined as follows:
```javascript
function add(global, _dispatch, n) {
return { count: global.count + n };
}
```
A reducer may be asynchronous (return a Promise) and asynchronously dispatch
other reducers. You can use a reducer that dispatches other reducers to create
a "saga" of state changes.
```javascript
async function mySaga(global, dispatch, shouldMultiply) {
if (global.count < 0) {
await dispatch.add(1);
}
await dispatch.subtract(2);
if (shouldMultiply) {
await dispatch.multiply(3);
}
}

mySaga(true); // shouldMultiply = true
```
#### Property Reducer
A property reducer is a reducer that only changes one property. They only
receive that property's value as a parameter instead of the entire global state
object, and they do not receive the dispatch object as a parameter at all.
An example "add" property reducer may be defined as follows:
```javascript
function add(count, n) {
return count + n;
}
```
You must specify the property when _using_ a property reducer. Property
reducers cannot be added to or remembered by the global state manager.
```javascript
import React, { useDispatch, useGlobal } from 'reactn';

function add(count, n) {
return count + n;
}

function MyComponent() {
const [ count ] = useGlobal('count');
// Use the "add" property reducer on the "count" property.
const dispatch = useDispatch(add, 'count');
return (
<button onClick={() => dispatch(1)}>
{count}
</button>
)
}
```
## Support
For support, reach out to us on the
Expand Down
6 changes: 5 additions & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module.exports = {
cacheDirectory: './jest/cache',
collectCoverage: true,
collectCoverage: false,
collectCoverageFrom: [
'src/**/*',
],
Expand All @@ -10,6 +10,10 @@ module.exports = {
resetModules: true,
restoreMocks: true,
roots: [ "<rootDir>/tests" ],
setupFilesAfterEnv: [
'@testing-library/jest-dom/extend-expect',
'@testing-library/react/cleanup-after-each',
],
testRegex: '/tests/.+\\.test\\.tsx?$',
verbose: false,
};
9 changes: 5 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "reactn",
"version": "2.1.5",
"version": "2.1.6",
"author": "Charles Stover <[email protected]>",
"description": "React, but with built-in global state management.",
"homepage": "https://github.com/CharlesStover/reactn#readme",
Expand Down Expand Up @@ -35,6 +35,8 @@
"@babel/core": "^7.4.0",
"@babel/preset-env": "^7.4.2",
"@babel/preset-typescript": "^7.3.3",
"@testing-library/jest-dom": "^4.0.0",
"@testing-library/react": "^8.0.5",
"@types/jest": "^24.0.11",
"@types/node": "^12.6.2",
"@types/react": "^16.7.13",
Expand All @@ -46,14 +48,13 @@
"jest": "^24.6.0",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-testing-library": "^6.0.4",
"ts-jest": "^24.0.1",
"ts-node": "^8.0.2",
"typescript": "^3.3.1"
},
"peerDependencies": {
"@types/react": "^16.8.0",
"react": "^16.3.0",
"react-dom": "^16.3.0"
"react": "*",
"react-dom": "*"
}
}
Loading

0 comments on commit 9821b9f

Please sign in to comment.