Skip to content

Commit 4a2aaa4

Browse files
committed
Bug fixes, refactoring, test coverage and better README
1 parent fa824da commit 4a2aaa4

16 files changed

+432
-208
lines changed

README.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# react-context-session
22
[![NPM](https://img.shields.io/npm/v/@peteck/react-context-session.svg)](https://www.npmjs.com/package/@peteck/react-context-session) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)
33

4-
react-context-session is designed to minimize the number of rerenders, but still offer an elegant API that make development easy and fast.
4+
react-context-session is designed to minimize the number of rerenders, but still offer an elegant type-strict API that make development easy and fast.
55
With one generic `useSession` hook, and one context provider `<ProvideSession />`, you will be up and ready to go, using your own session data structure.
66
The session state dispatcher makes sure that only the requested session data properties will cause the necessary side effects and rerendering.
77

@@ -57,7 +57,7 @@ function MyButton() {
5757
// * Mandatory: Set default session values in the data prop
5858
function MyApp() {
5959
return (
60-
<ProvideSession data={{ x: 5, y: 10, z: "My string" }}>
60+
<ProvideSession <MySessionType> data={{ x: 5, y: 10, z: "My string" }}>
6161
<MyCalculation />
6262
<MyMessage />
6363
<MyButton />
@@ -71,14 +71,14 @@ If your app has different sections where the session data should to be shared be
7171
for each section as following.
7272
```tsx
7373
function AdminSection() {
74-
return (
75-
<ProvideSession data={...} context={"admin"}>...</ProvideSession>
76-
)
74+
return (
75+
<ProvideSession <MySessionType> data={...} context={"admin"}>...</ProvideSession>
76+
)
7777
}
7878
function UserSection() {
79-
return (
80-
<ProvideSession data={...} context={"user"}>...</ProvideSession>
81-
)
79+
return (
80+
<ProvideSession <MySessionType> data={...} context={"user"}>...</ProvideSession>
81+
)
8282
}
8383
```
8484

@@ -94,11 +94,11 @@ type MySessionType = {
9494
};
9595

9696
function MyProvider() {
97-
const [defaultData, setDefaultData] = useState<MySessionType>();
97+
const [defaultData, setDefaultData] = useState<MySessionData>();
9898
useEffect(() => {
9999
AsyncStorage.getItem("session").then((value) => {
100100
if (value !== null) {
101-
setDefaultData(JSON.parse(value) as MySessionType);
101+
setDefaultData(JSON.parse(value) as MySessionData);
102102
} else {
103103
// If no session data was found in storage, we still need to give an default data set
104104
setDefaultData({

example/src/App.test.tsx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
// import React from 'react'
2-
// import ReactDOM from 'react-dom'
3-
// import App from './App'
4-
//
5-
// it('renders without crashing', () => {
6-
// const div = document.createElement('div')
7-
// ReactDOM.render(<App />, div)
8-
// ReactDOM.unmountComponentAtNode(div)
9-
// })
1+
import React from "react";
2+
import ReactDOM from "react-dom";
3+
import { App } from "./App";
4+
5+
it("renders without crashing", () => {
6+
const div = document.createElement("div");
7+
ReactDOM.render(<App />, div);
8+
ReactDOM.unmountComponentAtNode(div);
9+
});

example/src/App.tsx

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -137,42 +137,48 @@ export function Parent() {
137137
);
138138
}
139139

140-
const App = () => {
140+
export function App() {
141141
return (
142142
<div>
143143
<h1>react-context-session</h1>
144144
<code className={"code"}>
145-
{`type MySessionData = {
145+
{`type MySessionData = {
146146
a: number;
147147
b: number;
148148
c: number;
149149
};`}
150150
</code>
151151
<div className={"container"}>
152152
<div className={"context"}>
153-
<ProvideSession
153+
<ProvideSession<Test>
154154
data={{ a: 0, b: 0, c: 0 }}
155155
context={"app"}
156-
onChange={(data) => {
156+
onChange={async (data) => {
157157
console.log("Save to storage", data);
158158
}}>
159-
<h2><u>App</u> context</h2>
159+
<h2>
160+
<u>App</u> context
161+
</h2>
160162
<Parent />
161163
<Observer />
162164
</ProvideSession>
163165
</div>
164166
<div className={"context"}>
165-
<ProvideSession
167+
<ProvideSession<Test>
166168
data={{ a: 0, b: 0, c: 0 }}
167169
context={"admin"}>
168-
<h2><u>Admin</u> context</h2>
170+
<h2>
171+
<u>Admin</u> context
172+
</h2>
169173
<Parent />
170174
<Observer />
171175
</ProvideSession>
172176
</div>
173177
</div>
174178
</div>
175179
);
176-
};
180+
}
177181

178-
export default App;
182+
export function WithoutProvider() {
183+
return <Observer />;
184+
}

example/src/async-storage.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,18 @@ import React, { useEffect, useState } from "react";
22
import { ProvideSession } from "../../src";
33
import AsyncStorage from "@react-native-community/async-storage";
44

5-
type MySessionType = {
5+
type MySessionData = {
66
x: number;
77
y: number;
88
z: string;
99
};
1010

1111
export function MyProvider() {
12-
const [defaultData, setDefaultData] = useState<MySessionType>();
12+
const [defaultData, setDefaultData] = useState<MySessionData>();
1313
useEffect(() => {
1414
AsyncStorage.getItem("session").then((value) => {
1515
if (value !== null) {
16-
setDefaultData(JSON.parse(value) as MySessionType);
16+
setDefaultData(JSON.parse(value) as MySessionData);
1717
} else {
1818
// If no session data was found in storage, we still need to give an default data set
1919
setDefaultData({

example/src/getting-started.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ function MyButton() {
4141
// * Mandatory: Set default session values in the data prop
4242
function MyApp() {
4343
return (
44-
<ProvideSession data={{ x: 5, y: 10, z: "My string" }}>
44+
<ProvideSession<MySessionType> data={{ x: 5, y: 10, z: "My string" }}>
4545
<MyCalculation />
4646
<MyMessage />
4747
<MyButton />

example/src/index.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import "./index.css";
22

33
import React from "react";
44
import ReactDOM from "react-dom";
5-
import App from "./App";
6-
//import MyApp from './getting-started'
5+
import { App } from "./App";
76

87
ReactDOM.render(<App />, document.getElementById("root"));

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
"prettify": "prettier --write \"**/*.ts\" && prettier --write \"**/*.tsx\"",
2222
"test": "run-s test:unit test:lint test:build",
2323
"test:build": "run-s build",
24-
"test:lint": "eslint .",
24+
"test:lint": "eslint \"**/*.{ts,tsx}\"",
2525
"test:unit": "cross-env CI=1 react-scripts test --env=jsdom",
2626
"test:watch": "react-scripts test --env=jsdom",
2727
"predeploy": "cd example && yarn install && yarn run build",
@@ -40,7 +40,6 @@
4040
"@types/react-dom": "^16.9.7",
4141
"@typescript-eslint/eslint-plugin": "^2.26.0",
4242
"@typescript-eslint/parser": "^2.26.0",
43-
"microbundle-crl": "^0.13.10",
4443
"babel-eslint": "^10.0.3",
4544
"cross-env": "^7.0.2",
4645
"eslint": "^6.8.0",
@@ -54,6 +53,7 @@
5453
"eslint-plugin-react": "^7.17.0",
5554
"eslint-plugin-standard": "^4.0.1",
5655
"gh-pages": "^2.2.0",
56+
"microbundle-crl": "^0.13.10",
5757
"npm-run-all": "^4.1.5",
5858
"prettier": "^2.0.4",
5959
"react": "^16.13.1",
@@ -63,5 +63,6 @@
6363
},
6464
"files": [
6565
"dist"
66-
]
66+
],
67+
"dependencies": {}
6768
}

src/dispatcher.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import {
2+
SessionDispatchFunc,
3+
SessionGenericData,
4+
SessionValueType,
5+
} from "./types";
6+
7+
export class Dispatcher<DataType extends SessionGenericData> {
8+
dispatchers: Partial<
9+
{
10+
[key in keyof DataType]: [SessionDispatchFunc];
11+
}
12+
> = {};
13+
14+
dispatch(key: keyof DataType, value: SessionValueType): void {
15+
if (typeof this.dispatchers[key] === "undefined") {
16+
return;
17+
}
18+
19+
for (let i = 0; i < this.dispatchers[key]!.length; i++) {
20+
this.dispatchers[key][i](value);
21+
}
22+
}
23+
24+
register(key: keyof DataType, dispatchFunc: SessionDispatchFunc): void {
25+
if (typeof this.dispatchers[key] === "undefined") {
26+
this.dispatchers[key] = [dispatchFunc];
27+
} else {
28+
this.dispatchers[key]!.push(dispatchFunc);
29+
}
30+
}
31+
32+
unregister(key: keyof DataType, dispatchFunc: SessionDispatchFunc): void {
33+
if (typeof this.dispatchers[key] === "undefined") {
34+
return;
35+
}
36+
37+
for (let j = 0; j < this.dispatchers[key]!.length; j++) {
38+
if (this.dispatchers[key][j] === dispatchFunc) {
39+
this.dispatchers[key]!.splice(j, 1);
40+
}
41+
}
42+
}
43+
}

0 commit comments

Comments
 (0)