Skip to content

Commit c00a507

Browse files
author
Jack Ellis
committed
feat: encase method
a react context-aware version of jpex.encase
1 parent 312ba58 commit c00a507

File tree

8 files changed

+183
-16
lines changed

8 files changed

+183
-16
lines changed

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,24 @@ const Page = () => {
4949
};
5050
```
5151

52+
## Encase
53+
```ts
54+
(...deps: any[]): (...args: any[]) => any
55+
```
56+
This is the same as jpex's own `encase` method, but uses the react context to use the correct jpex instance.
57+
58+
You can encase both hooks and entire components:
59+
```ts
60+
const useLocation = encase((window: Window) => () => window.location);
61+
```
62+
```tsx
63+
const MyComponent = encase((window: Window) => () => (
64+
<div>{window.location.pathname}</div>
65+
));
66+
```
67+
68+
For more info see https://github.com/jpex-js/jpex#jpexencase
69+
5270
## Provider
5371
```ts
5472
ComponentType<{

package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"version": "1.3.0",
44
"main": "dist/cjs/react-jpex.js",
55
"module": "dist/es/react-jpex.js",
6-
"types": "dist/es/index.d.ts",
6+
"types": "dist/ts/index.d.ts",
77
"repository": "git@github.com:jpex-js/react-jpex.git",
88
"author": "Jack Ellis <jack.ellis@godaddy.com>",
99
"license": "MIT",
@@ -13,7 +13,7 @@
1313
"test": "ava",
1414
"build:prepare": "rm -rf dist",
1515
"build:js": "rollup -c",
16-
"build:ts": "tsc -d --outDir dist/es --emitDeclarationOnly",
16+
"build:ts": "tsc -d --outDir dist/ts --emitDeclarationOnly",
1717
"build:post": "node ./postbuild-checks.js",
1818
"build": "yarn build:prepare && yarn build:js && yarn build:ts && yarn build:post",
1919
"prepublishOnly": "yarn build"
@@ -25,7 +25,7 @@
2525
"@babel/preset-typescript": "^7.10.4",
2626
"@babel/register": "^7.11.5",
2727
"@commitlint/config-conventional": "^9.1.2",
28-
"@jpex-js/babel-plugin": "^1.0.0",
28+
"@jpex-js/babel-plugin": "^1.4.0",
2929
"@team-griffin/eslint-config": "^3.3.0",
3030
"@testing-library/react": "^11.1.1",
3131
"@testing-library/react-hooks": "^3.4.1",
@@ -35,7 +35,7 @@
3535
"ava": "^3.12.1",
3636
"browser-env": "^3.3.0",
3737
"eslint": "^7.8.1",
38-
"jpex": "^4.1.0",
38+
"jpex": "^4.3.0",
3939
"module-alias": "^2.2.2",
4040
"nyc": "^15.1.0",
4141
"react": "^17.0.1",
@@ -48,7 +48,7 @@
4848
"typescript": "^4.0.5"
4949
},
5050
"peerDependencies": {
51-
"jpex": "^4.1.0",
51+
"jpex": "^4.3.0",
5252
"react": "^16.8.0 || ^17.0.0"
5353
}
5454
}

postbuild-checks.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@ const jpex = require('./dist/cjs/react-jpex');
44
const expectedFiles = [
55
'dist/cjs/react-jpex.js',
66
'dist/es/react-jpex.js',
7-
'dist/es/index.d.ts',
7+
'dist/ts/index.d.ts',
88
];
99
const expectedExports = [
1010
[ 'useJpex', '[object Function]' ],
1111
[ 'useResolve', '[object Function]' ],
1212
[ 'Provider', '[object Function]' ],
13+
[ 'useRegister', '[object Function]' ],
14+
[ 'encase', '[object Function]' ],
1315
];
1416

1517
const run = async() => {

src/__tests__/encase.test.tsx

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
import React, { useRef } from 'react';
2+
import test from 'ava';
3+
import { Provider, encase } from 'react-jpex';
4+
import { renderHook } from '@testing-library/react-hooks';
5+
import { render, screen, cleanup } from '@testing-library/react';
6+
import jpex from 'jpex';
7+
8+
const baseJpex = jpex;
9+
10+
test.afterEach(cleanup);
11+
12+
test.serial('injects dependencies into a hook', (t) => {
13+
type Foo = string;
14+
const useFoo = encase((foo: Foo) => () => {
15+
// just for the sake of proving this is a react hook
16+
const ref = useRef(foo);
17+
return ref.current;
18+
});
19+
20+
const { result: { current } } = renderHook(useFoo, {
21+
wrapper: Provider,
22+
initialProps: {
23+
onMount(jpex) {
24+
jpex.constant<Foo>('foo');
25+
},
26+
},
27+
});
28+
29+
t.is(current, 'foo');
30+
});
31+
32+
test.serial('injects dependencies into a component', async(t) => {
33+
type Foo = string;
34+
const Component = encase((foo: Foo) => (props: { bar: string }) => {
35+
const ref = useRef(props.bar);
36+
37+
return (
38+
<div>
39+
<span>{ref.current}</span>
40+
<span>{foo}</span>
41+
</div>
42+
);
43+
});
44+
45+
render(
46+
<Provider onMount={(jpex) => jpex.constant<Foo>('foo')}>
47+
<Component bar="bar"/>
48+
</Provider>
49+
);
50+
51+
await screen.findByText('foo');
52+
await screen.findByText('bar');
53+
54+
t.pass();
55+
});
56+
57+
test.serial('when props change it still works', async(t) => {
58+
type Foo = string;
59+
const Component = encase((foo: Foo) => (props: { bar: string }) => {
60+
return (
61+
<div>
62+
<span>{props.bar}</span>
63+
<span>{foo}</span>
64+
</div>
65+
);
66+
});
67+
68+
const { rerender } = render(
69+
<Provider onMount={(jpex) => jpex.constant<Foo>('foo')}>
70+
<Component bar="bar"/>
71+
</Provider>
72+
);
73+
74+
await screen.findByText('foo');
75+
await screen.findByText('bar');
76+
77+
rerender(
78+
<Provider onMount={(jpex) => jpex.constant<Foo>('foo')}>
79+
<Component bar="baz"/>
80+
</Provider>
81+
);
82+
83+
await screen.findByText('foo');
84+
await screen.findByText('baz');
85+
86+
t.pass();
87+
});
88+
89+
test.serial('nested encases', async(t) => {
90+
const jpex = baseJpex.extend();
91+
92+
type Foo = string;
93+
jpex.constant<Foo>('foo');
94+
95+
const useFoo = encase((foo: Foo) => () => {
96+
// just for the sake of proving this is a react hook
97+
const ref = useRef(foo);
98+
return ref.current;
99+
});
100+
type UseFoo = typeof useFoo;
101+
jpex.constant<UseFoo>(useFoo);
102+
103+
const Component = encase((useFoo: UseFoo) => () => {
104+
const foo = useFoo();
105+
106+
return (
107+
<div>
108+
<span>{foo}</span>
109+
</div>
110+
);
111+
});
112+
113+
render(
114+
<Provider value={jpex}>
115+
<Component/>
116+
</Provider>
117+
);
118+
119+
await screen.findByText('foo');
120+
121+
t.pass();
122+
});

src/encase.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import jpex from 'jpex';
2+
import { useRef } from 'react';
3+
import useJpex from './useJpex';
4+
5+
type Encase = typeof jpex.encase;
6+
7+
function encase(
8+
dependencies: string[],
9+
fn: (...args: any[]) => any
10+
) {
11+
function encased(...args: any[]) {
12+
const jpex = useJpex();
13+
const fnRef = useRef<any>();
14+
if (fnRef.current == null) {
15+
const deps = dependencies.map((name) => jpex.resolve(name));
16+
fnRef.current = fn.apply(jpex, deps);
17+
}
18+
return fnRef.current.apply(null, args);
19+
}
20+
encased.encased = fn;
21+
return encased;
22+
}
23+
24+
export default encase as Encase;

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
export { default as encase } from './encase';
12
export { default as Provider } from './Provider';
23
export { default as useJpex } from './useJpex';
34
export { default as useRegister } from './useRegister';

src/useRegister.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Jpex } from 'jpex';
2-
import { useJpex } from '.';
2+
import useJpex from './useJpex';
33
import { useRef } from 'react';
44

55
export default function useRegister(...fns: ((jpex: Jpex) => void)[]) {

yarn.lock

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1140,10 +1140,10 @@
11401140
"@types/yargs" "^15.0.0"
11411141
chalk "^4.0.0"
11421142

1143-
"@jpex-js/babel-plugin@^1.0.0":
1144-
version "1.1.0"
1145-
resolved "https://registry.yarnpkg.com/@jpex-js/babel-plugin/-/babel-plugin-1.1.0.tgz#9349a59f83df40f9daeec98fdc8241f960710a32"
1146-
integrity sha512-TTyl9yri/VbJO9UCvGsr8KYY0rkuh/vT9T5TBEXXAHkosb29eY9LTvO3diEbGpoJ6aAilhSzMfCmvbuzjH+IDQ==
1143+
"@jpex-js/babel-plugin@^1.3.0", "@jpex-js/babel-plugin@^1.4.0":
1144+
version "1.4.0"
1145+
resolved "https://registry.yarnpkg.com/@jpex-js/babel-plugin/-/babel-plugin-1.4.0.tgz#50a6fb6a8730342ac603792a5a452471229b16d1"
1146+
integrity sha512-AApf6F2LtAG4oDmatcHrye0R1VPLyAnFLR3ktqts+MVQV7RHGWfcpfQ8RNcfn/JXEIySsMXzMe5G3nywB8reXQ==
11471147

11481148
"@nodelib/fs.scandir@2.1.3":
11491149
version "2.1.3"
@@ -4757,12 +4757,12 @@ java-properties@^1.0.0:
47574757
resolved "https://registry.yarnpkg.com/java-properties/-/java-properties-1.0.2.tgz#ccd1fa73907438a5b5c38982269d0e771fe78211"
47584758
integrity sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ==
47594759

4760-
jpex@^4.1.0:
4761-
version "4.1.0"
4762-
resolved "https://registry.yarnpkg.com/jpex/-/jpex-4.1.0.tgz#41b08ed31b8f7779ab78e09be446f6eabd780845"
4763-
integrity sha512-icRsf6ZMzjEzUCF6NrzJ4kDM3M4t2SGRnA7TajjO6NH5cCdnBLZWy/ggbYqVQgMeBx+PzHgdsljJdaID2WdGbw==
4760+
jpex@^4.3.0:
4761+
version "4.3.0"
4762+
resolved "https://registry.yarnpkg.com/jpex/-/jpex-4.3.0.tgz#dbebd5377e56f3be71b58b5bbedb49aa2025c2cf"
4763+
integrity sha512-+nJINRDmmdBjNVFgVziLeEfhBFZ3YD/LmFzz0ZmHRg1QVtWdH3ebNDgGVUIuRHoUrSsQFTgErl+YI8QsdG/nYQ==
47644764
dependencies:
4765-
"@jpex-js/babel-plugin" "^1.0.0"
4765+
"@jpex-js/babel-plugin" "^1.3.0"
47664766

47674767
js-string-escape@^1.0.1:
47684768
version "1.0.1"

0 commit comments

Comments
 (0)