Skip to content

Commit 6887768

Browse files
authored
Add React 18+ support (#45)
1 parent fc0f1a2 commit 6887768

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+12705
-14085
lines changed

.eslintrc.js

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
module.exports = {
2+
env: {
3+
browser: true,
4+
es2021: true,
5+
node: true,
6+
},
7+
extends: [
8+
'xo',
9+
'plugin:react/recommended',
10+
],
11+
overrides: [
12+
{
13+
env: {
14+
node: true,
15+
},
16+
files: [
17+
'.eslintrc.{js,cjs}',
18+
],
19+
parserOptions: {
20+
sourceType: 'script',
21+
},
22+
},
23+
{
24+
extends: [
25+
'xo-typescript',
26+
],
27+
files: [
28+
'*.ts',
29+
'*.tsx',
30+
],
31+
},
32+
{
33+
files: [
34+
'*.ts',
35+
'*.tsx',
36+
],
37+
StrictPascalCase: false,
38+
},
39+
],
40+
parserOptions: {
41+
ecmaVersion: 'latest',
42+
sourceType: 'module',
43+
},
44+
plugins: [
45+
'react',
46+
],
47+
rules: {
48+
},
49+
};

.github/workflows/nodejs.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
22
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
33

4-
name: Node.js CI
4+
name: CI
55

66
on:
77
push:
@@ -16,12 +16,12 @@ jobs:
1616

1717
strategy:
1818
matrix:
19-
node-version: [10.x, 12.x]
19+
node-version: [16.x, 17.x, 18.x, 20.x, 22.x]
2020

2121
steps:
2222
- uses: actions/checkout@v2
2323
- name: Use Node.js ${{ matrix.node-version }}
24-
uses: actions/setup-node@v1
24+
uses: actions/setup-node@v3
2525
with:
2626
node-version: ${{ matrix.node-version }}
2727
- run: npm ci

.github/workflows/npmpublish.yml

+4-4
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ jobs:
1212
runs-on: ubuntu-latest
1313
steps:
1414
- uses: actions/checkout@v2
15-
- uses: actions/setup-node@v1
15+
- uses: actions/setup-node@v3
1616
with:
17-
node-version: 12
17+
node-version-file: ".nvmrc"
1818
- run: npm ci
1919
- run: npm run build
2020
- run: npm test
@@ -24,9 +24,9 @@ jobs:
2424
runs-on: ubuntu-latest
2525
steps:
2626
- uses: actions/checkout@v2
27-
- uses: actions/setup-node@v1
27+
- uses: actions/setup-node@v3
2828
with:
29-
node-version: 12
29+
node-version-file: ".nvmrc"
3030
registry-url: https://registry.npmjs.org/
3131
- run: npm ci
3232
- run: npm run build

.github/workflows/playwright.yml

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
name: Playwright Tests
2+
on:
3+
push:
4+
5+
jobs:
6+
test:
7+
timeout-minutes: 60
8+
runs-on: ubuntu-latest
9+
steps:
10+
- uses: actions/checkout@v3
11+
- uses: actions/setup-node@v3
12+
with:
13+
node-version-file: ".nvmrc"
14+
- name: Install dependencies
15+
run: npm ci
16+
- name: Install Playwright Browsers
17+
run: npx playwright install --with-deps
18+
- name: Run Playwright tests
19+
run: npx playwright test
20+
- uses: actions/upload-artifact@v3
21+
if: always()
22+
with:
23+
name: playwright-report
24+
path: playwright-report/
25+
retention-days: 30

.gitignore

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
11
node_modules
22
dist
3-
example/build
3+
example/build
4+
dist-server
5+
/test-results/
6+
/playwright-report/
7+
/playwright/.cache/
8+
/*.scratchpad.*

.nvmrc

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
v22.3

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## 3.x.x
4+
5+
## 3.0.0 Bling bang bang born
6+
37
## 2.x.x
48

59
### 2.0.x

README.md

+61-104
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
1-
# useSSE
1+
# useSSE 3.x.x-beta
2+
3+
> [!CAUTION]
4+
> 3.x.x is still in beta
5+
6+
> [!NOTE]
7+
> You are viewing a v3.x.x version of hook which is designed to be compatible with React 18. This version of hook is still in beta.
8+
> If you are using React <18 check latest stable [2.x.x version of useSSE](https://github.com/kmoskwiak/useSSE/tree/v2.0.1)
29
310
![useSSE](https://repository-images.githubusercontent.com/262809605/78398700-a279-11ea-9ba2-4c15b6a1ec9a)
411
[![npm version](https://badgen.net/npm/v/use-sse)](https://www.npmjs.com/package/use-sse)
5-
![Node.js CI](https://github.com/kmoskwiak/useSSE/workflows/Node.js%20CI/badge.svg?branch=master)
12+
![Node.js CI](https://github.com/kmoskwiak/useSSE/workflows/CI/badge.svg?branch=master)
613

714
`useSSE` is abbreviation for use server-side effect. It is a custom React hook to perform asynchronous effects both on client and serve side.
815

@@ -15,58 +22,77 @@ npm i use-sse
1522
Use `useSSE` to fetch data in component:
1623

1724
```jsx
18-
import React from "react";
1925
import { useSSE } from "use-sse";
2026

21-
const MyComponent = () => {
27+
/**
28+
* Create a custom component with effect
29+
**/
30+
const TitleComponent = () => {
2231
const [data, error] = useSSE(() => {
2332
return fetch("https://myapi.example.com").then((res) => res.json());
2433
}, []);
2534

26-
return <div>{data.title}</div>;
35+
return <h1>{data.title}</h1>;
2736
};
28-
```
2937

30-
All effects will be resolved on server side during rendering.
38+
/**
39+
* To take full advantage of a Suspense boundaries wrap each component in UniversalDataProvider
40+
* You can also use ServerDataProvider or BrowserDataProvider
41+
**/
42+
export const Title = () => {
43+
return (
44+
<UniversalDataProvider>
45+
<TitleComponent />
46+
</UniversalDataProvider>
47+
)
48+
}
49+
```
3150

32-
This is a part of server side render phase. Se an example for the whole code.
51+
Load component using Suspense API:
3352

34-
```js
35-
const { ServerDataContext, resolveData } = createServerContext();
36-
37-
// We need to render app twice.
38-
// First - render App to reqister all effects
39-
renderToString(
40-
<ServerDataContext>
41-
<App />
42-
</ServerDataContext>
53+
```jsx
54+
import * as React from 'react';
55+
import Title from './Title';
56+
57+
export const App = () => (
58+
<div>
59+
<React.Suspense fallback={'Loading...'}>
60+
<Title/>
61+
</React.Suspense>
62+
</div>
4363
);
64+
```
4465

45-
// Wait for all effects to finish
46-
const data = await resolveData();
66+
All effects will be resolved on server side during rendering.
4767

48-
// Inject into html initial data
49-
res.write(data.toHtml());
68+
This is a part of server side render phase. See an example for the whole code.
5069

51-
// Render App for the second time
52-
// This time data form effects will be avaliable in components
53-
const htmlStream = renderToNodeStream(
54-
<ServerDataContext>
55-
<App />
56-
</ServerDataContext>
57-
);
70+
```jsx
71+
const stream = renderToPipeableStream(
72+
<App />,
73+
{
74+
onShellReady() {
75+
res.statusCode = didError ? 500 : 200;
76+
res.setHeader('Content-type', 'text/html');
77+
stream.pipe(res);
78+
},
79+
onShellError() {
80+
res.statusCode = 500;
81+
res.send('<h1>An error occurred</h1>');
82+
},
83+
onError(err) {
84+
didError = true;
85+
console.error(err);
86+
},
87+
},
88+
);
5889
```
5990

6091
On client side of application use `BroswerDataContext`:
6192

62-
```js
63-
// This will create context will all data fetched during server side rendering
64-
const BroswerDataContext = createBroswerContext();
65-
93+
```jsx
6694
hydrate(
67-
<BroswerDataContext>
68-
<App />
69-
</BroswerDataContext>,
95+
<App />,
7096
document.getElementById("app")
7197
);
7298
```
@@ -93,76 +119,7 @@ Returns an array with two elements `[data, error]`.
93119
- `data` - resolved response from effect
94120
- `error` - an error if effect rejected or if timeout happend.
95121

96-
---
97-
98-
### createServerContext()
99-
100-
Creates server side context.
101-
102-
```js
103-
const { ServerDataContext, resolveData } = createServerContext();
104-
```
105-
106-
#### Returns
107-
108-
`ServerDataContext` - React context provider component.
109-
110-
```html
111-
<ServerDataContext>
112-
<App />
113-
</ServerDataContext>
114-
```
115122

116-
`resolveData` - function to resolve all effects.
117-
118-
```js
119-
const data = await resolveData(timeout);
120-
```
121-
122-
| param | type | required | default value | description |
123-
| --------- | -------- | -------- | ------------- | ----------------------------------------------- |
124-
| `timeout` | `number` | false | `undefined` | max number of ms to wait for effects to resolve |
125-
126-
`data` is an object containing value of context.
127-
128-
Calling `data.toHtml(variableName)` will return a html script tak with stringified data:
129-
130-
| param | type | required | default value | description |
131-
| -------------- | -------- | -------- | -------------------- | ----------------------- |
132-
| `variableName` | `string` | false | \_initialDataContext | name of global variable |
133-
134-
```js
135-
data.toHtml();
136-
// "<script>window._initialDataContext = { context data };</script>"
137-
```
138-
139-
Both should be used in server side render function.
140-
141-
---
142-
143-
### createBroswerContext()
144-
145-
Creates client side context.
146-
147-
```js
148-
createBroswerContext(variableName);
149-
```
150-
151-
#### params
152-
153-
| param | type | required | default value | description |
154-
| -------------- | -------- | -------- | -------------------- | ----------------------- |
155-
| `variableName` | `string` | false | \_initialDataContext | name of global variable |
156-
157-
#### returns
158-
159-
`BroswerDataContext` - React context provider for client side application
160-
161-
```html
162-
<BroswerDataContext>
163-
<App />
164-
</BroswerDataContext>
165-
```
166123

167124
## Examples
168125

babel.config.json

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"presets": [
3+
"@babel/env",
4+
[
5+
"@babel/preset-react",
6+
{
7+
"runtime": "automatic"
8+
}
9+
],
10+
"@babel/preset-typescript"
11+
]
12+
}

e2e/example.spec.ts

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { test, expect } from '@playwright/test';
2+
3+
test('renders data from success response', async ({ page }) => {
4+
await page.goto('http://localhost:3000/');
5+
6+
const container = await page.getByTestId('data');
7+
8+
await expect(container).toHaveText(/Jake The Dog Stretching/);
9+
});
10+
11+
test('handles error from effect', async ({ page }) => {
12+
await page.goto('http://localhost:3000/');
13+
14+
const container = await page.getByTestId('error');
15+
16+
await expect(container).toHaveText(/Error/);
17+
});
18+
19+
20+
test('renders data from endpoint with timeout', async ({ page }) => {
21+
await page.goto('http://localhost:3000/');
22+
23+
const container = await page.getByTestId('long');
24+
25+
await expect(container).toHaveText(/Finn The Human Sword Fighting/);
26+
});

example/.babelrc

-3
This file was deleted.

0 commit comments

Comments
 (0)