Skip to content
This repository was archived by the owner on Jan 7, 2025. It is now read-only.

Commit 79da7db

Browse files
authored
Merge pull request #4 from soywod/develop
Release v1.1.0
2 parents a11cd09 + 1ee710e commit 79da7db

File tree

5 files changed

+60
-35
lines changed

5 files changed

+60
-35
lines changed

CHANGELOG.md

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,31 +7,43 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [1.1.0] - 2022-05-27
11+
12+
### Added
13+
14+
- Motivation and Similar projects section in readme.
15+
16+
### Changed
17+
18+
- The `EffectReducer` takes now a second argument dispatch of type
19+
`React.Dispatch<Action>`.
20+
1021
## [1.0.5] - 2022-05-26
1122

1223
### Fix
1324

14-
- Export only UMD and ESM formats
25+
- Export only UMD and ESM formats.
1526

1627
## [1.0.4] - 2022-05-26
1728

1829
### Fix
1930

20-
- Modern js export
31+
- Fix modern js export.
2132

2233
## [1.0.3] - 2022-05-26
2334

2435
### Fix
2536

26-
- Microbundle export names
37+
- Fix Microbundle export names.
2738

2839
## [1.0.2] - 2022-05-26
2940

3041
## [1.0.1] - 2022-05-26
3142

3243
## [1.0.0] - 2022-05-26
3344

34-
[unreleased]: https://github.com/soywod/react-use-bireducer/compare/v1.0.5...HEAD
45+
[unreleased]: https://github.com/soywod/react-use-bireducer/compare/v1.1.0...HEAD
46+
[1.1.0]: https://github.com/soywod/react-use-bireducer/compare/v1.0.5...v1.1.0
3547
[1.0.5]: https://github.com/soywod/react-use-bireducer/compare/v1.0.4...v1.0.5
3648
[1.0.4]: https://github.com/soywod/react-use-bireducer/compare/v1.0.3...v1.0.4
3749
[1.0.3]: https://github.com/soywod/react-use-bireducer/compare/v1.0.2...v1.0.3

README.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ The effect reducer just executes effects and can return a cleanup
2323
function. This cleanup function is called when the component unmounts:
2424

2525
```typescript
26-
type EffectReducer<E> = (effect: E) => void | (() => void);
26+
type EffectReducer<E, A> = (effect: E, dispatch: React.Dispatch<A>) => void | (() => void);
2727
```
2828

2929
This pattern helps you to separate state changes from effectful
@@ -91,6 +91,14 @@ Library](https://testing-library.com/docs/react-testing-library/intro/)
9191
yarn test
9292
```
9393

94+
## Similar projects
95+
96+
- [`useEffectReducer`](https://github.com/davidkpiano/useEffectReducer):
97+
the state reducer exposes a third argument called `exec` to schedule
98+
effects
99+
- [`useElmish`](https://github.com/ncthbrt/react-use-elmish): it is a
100+
mix between `useEffectReducer` and `useBireducer`
101+
94102
## Sponsoring
95103

96104
[![github](https://img.shields.io/badge/-GitHub%20Sponsors-fafbfc?logo=GitHub%20Sponsors&style=flat-square)](https://github.com/sponsors/soywod)

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "react-use-bireducer",
33
"author": "soywod <clement.douin@posteo.net>",
44
"description": "React hook for managing effects from reducers.",
5-
"version": "1.0.5",
5+
"version": "1.1.0",
66
"license": "MIT",
77
"source": "src/index.ts",
88
"typings": "dist/index.d.ts",

src/index.spec.tsx

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,30 +8,18 @@ type State = {
88
count: number;
99
};
1010

11-
type Action =
12-
| {type: "increment"; value: number}
13-
| {type: "decrement"; value: number}
14-
| {type: "reset"};
11+
type Action = {type: "update"; value: number} | {type: "reset"};
1512

1613
type Effect = {type: "log"; value: string} | {type: "backup"; count: number};
1714

1815
const stateReducer: StateReducer<State, Action, Effect> = (state, action) => {
1916
switch (action.type) {
20-
case "increment": {
21-
return [
22-
{count: state.count + action.value},
23-
[{type: "log", value: `increment counter +${action.value}`}],
24-
];
25-
}
26-
case "decrement": {
27-
return [
28-
{count: state.count - action.value},
29-
[{type: "log", value: `decrement counter -${action.value}`}],
30-
];
17+
case "update": {
18+
return [{count: action.value}, [{type: "log", value: `set counter ${action.value}`}]];
3119
}
3220
case "reset": {
3321
return [
34-
{count: 0},
22+
state,
3523
[
3624
{type: "log", value: "reset counter"},
3725
{type: "backup", count: state.count},
@@ -41,14 +29,15 @@ const stateReducer: StateReducer<State, Action, Effect> = (state, action) => {
4129
}
4230
};
4331

44-
const effectReducer: EffectReducer<Effect> = effect => {
32+
const effectReducer: EffectReducer<Effect, Action> = (effect, dispatch) => {
4533
switch (effect.type) {
4634
case "log": {
4735
console.log(effect.value);
4836
return;
4937
}
5038
case "backup": {
5139
localStorage.setItem("backup", String(effect.count));
40+
dispatch({type: "update", value: 0});
5241
return () => {
5342
localStorage.clear();
5443
};
@@ -80,9 +69,21 @@ describe("useBireducer", () => {
8069
return (
8170
<>
8271
<span data-testid="counter">{state.count}</span>
83-
<button data-testid="decrement" onClick={() => dispatch({type: "decrement", value: 1})} />
84-
<button data-testid="increment" onClick={() => dispatch({type: "increment", value: 1})} />
85-
<button data-testid="reset" onClick={() => dispatch({type: "reset"})} />
72+
<button
73+
data-testid="decrement"
74+
onClick={() => dispatch({type: "update", value: state.count - 1})}
75+
>
76+
decrement
77+
</button>
78+
<button
79+
data-testid="increment"
80+
onClick={() => dispatch({type: "update", value: state.count + 1})}
81+
>
82+
increment
83+
</button>
84+
<button data-testid="reset" onClick={() => dispatch({type: "reset"})}>
85+
reset
86+
</button>
8687
</>
8788
);
8889
}
@@ -93,15 +94,17 @@ describe("useBireducer", () => {
9394
fireEvent.click(screen.getByTestId("increment"));
9495
fireEvent.click(screen.getByTestId("increment"));
9596
expect(screen.getByTestId("counter")).toHaveTextContent("2");
96-
expect(console.log).toHaveBeenNthCalledWith(2, "increment counter +1");
97+
expect(console.log).toHaveBeenNthCalledWith(1, "set counter 1");
98+
expect(console.log).toHaveBeenNthCalledWith(2, "set counter 2");
9799

98100
fireEvent.click(screen.getByTestId("decrement"));
99101
expect(screen.getByTestId("counter")).toHaveTextContent("1");
100-
expect(console.log).toHaveBeenLastCalledWith("decrement counter -1");
102+
expect(console.log).toHaveBeenNthCalledWith(3, "set counter 1");
101103

102104
fireEvent.click(screen.getByTestId("reset"));
103105
expect(screen.getByTestId("counter")).toHaveTextContent("0");
104-
expect(console.log).toHaveBeenLastCalledWith("reset counter");
106+
expect(console.log).toHaveBeenNthCalledWith(4, "reset counter");
107+
expect(console.log).toHaveBeenNthCalledWith(5, "set counter 0");
105108
expect(localStorage.setItem).toHaveBeenNthCalledWith(1, "backup", "1");
106109
expect(localStorage.clear).not.toHaveBeenCalled();
107110

src/index.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
import {useCallback, useEffect, useReducer, useRef, useState} from "react";
1+
import {Dispatch, useCallback, useEffect, useReducer, useRef, useState} from "react";
22

33
export type StateReducer<S, A, E> = (state: S, action: A) => [S, E[]];
44

5-
export type EffectReducer<E> = (effect: E) => EffectCleanup | void;
5+
export type EffectReducer<E, A> = (effect: E, dispatch: Dispatch<A>) => EffectCleanup | void;
66
export type EffectCleanup = () => void;
77

88
export function useBireducer<S, A, E>(
99
stateReducer: StateReducer<S, A, E>,
10-
effectReducer: EffectReducer<E>,
10+
effectReducer: EffectReducer<E, A>,
1111
defaultState: S,
12-
) {
12+
): [S, Dispatch<A>] {
1313
const [effects, setEffects] = useState<E[]>([]);
1414
const cleanups = useRef<EffectCleanup[]>([]);
1515

@@ -22,10 +22,12 @@ export function useBireducer<S, A, E>(
2222
[stateReducer],
2323
);
2424

25+
const [state, dispatch] = useReducer(reducer, defaultState);
26+
2527
useEffect(() => {
2628
const effect = effects.pop();
2729
if (effect) {
28-
const cleanup = effectReducer(effect);
30+
const cleanup = effectReducer(effect, dispatch);
2931
if (cleanup) cleanups.current.push(cleanup);
3032
setEffects([...effects]);
3133
}
@@ -39,7 +41,7 @@ export function useBireducer<S, A, E>(
3941
};
4042
}, []);
4143

42-
return useReducer(reducer, defaultState);
44+
return [state, dispatch];
4345
}
4446

4547
export default {useBireducer};

0 commit comments

Comments
 (0)