Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions examples/06-suspense-like/.babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "usage"
}
],
"@babel/preset-typescript",
"@babel/preset-react"
],
"plugins": [
"@babel/proposal-class-properties",
"@babel/proposal-object-rest-spread"
]
}
49 changes: 49 additions & 0 deletions examples/06-suspense-like/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"name": "06-suspense-like",
"version": "1.0.0",
"description": "React Promise Tracker sample with suspense-like component",
"keywords": [
"react",
"promise",
"tracker",
"hook",
"hooks",
"typescript"
],
"author": "Javier Calzado (javi.calzado@lemoncode.net)",
"license": "MIT",
"main": "src/index.tsx",
"scripts": {
"start": "webpack-dev-server --mode development --inline --hot --open",
"typecheck": "tsc --pretty --noEmit",
"build": "npm run typecheck && webpack --mode development"
},
"dependencies": {
"@babel/polyfill": "^7.2.5",
"@material-ui/core": "3.9.3",
"react": "16.8.4",
"react-dom": "16.8.4",
"react-promise-tracker": "2.0.2"
},
"devDependencies": {
"@babel/cli": "^7.2.3",
"@babel/core": "^7.2.2",
"@babel/plugin-proposal-class-properties": "^7.1.0",
"@babel/plugin-proposal-object-rest-spread": "^7.0.0",
"@babel/preset-env": "^7.3.1",
"@babel/preset-react": "^7.0.0",
"@babel/preset-typescript": "^7.3.3",
"@types/node": "11.13.4",
"@types/react": "16.8.8",
"@types/react-dom": "16.8.2",
"babel-loader": "^8.0.6",
"core-js": "^2.6.5",
"html-webpack-plugin": "^3.2.0",
"tslint": "^5.16.0",
"tslint-react": "^4.0.0",
"typescript": "^3.4.5",
"webpack": "^4.29.3",
"webpack-cli": "^3.2.3",
"webpack-dev-server": "^3.1.14"
}
}
24 changes: 24 additions & 0 deletions examples/06-suspense-like/src/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const fetchWithDelay = (url: string, delay: number): Promise<Response> =>
new Promise(resolve => setTimeout(() => resolve(fetch(url, { method: "GET" })), delay));

export interface Quote {
body: string;
author: string;
}

export const getQuote = () =>
fetchWithDelay("https://favqs.com/api/qotd", Math.random() * 3000)
.then(result => result.json())
.then<{ quote: Quote }>(result => result.quote);

const arrayBufferToBase64 = buffer => {
let binary = "";
const bytes = [].slice.call(new Uint8Array(buffer));
bytes.forEach(b => (binary += String.fromCharCode(b)));
return window.btoa(binary);
};

export const getPicture = (width: number, height: number) =>
fetchWithDelay(`https://picsum.photos/${width}/${height}`, Math.random() * 3000).then(res =>
res.arrayBuffer().then(buffer => "data:image/jpeg;base64," + arrayBufferToBase64(buffer))
);
40 changes: 40 additions & 0 deletions examples/06-suspense-like/src/app.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import * as React from "react";
import CircularProgress from "@material-ui/core/CircularProgress";
import Typography from "@material-ui/core/Typography";
import Button from "@material-ui/core/Button";
import { WithStyles, withStyles } from "@material-ui/core/styles";
import { trackPromise, usePromiseTracker } from "react-promise-tracker";
import { Quote, getQuote, getPicture } from "./api";
import { styles } from "./styles";


const Suspense: React.FC<{ tag: string, className?: string }> = ({ tag, className, children }) => {
const { promiseInProgress } = usePromiseTracker({ area: tag });
return promiseInProgress ? <CircularProgress className={className} size={60}/> : <>{children}</>;
};

const AppInner: React.FC<WithStyles<typeof styles>> = ({classes}) => {
const [quote, setQuote] = React.useState<Quote>({ body: "", author: "" });
const [picture, setPicture] = React.useState();
const loadData = React.useCallback(() => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you use useCallback?

useCallback is to memoize the function by some params, but if you pass [] only memoize once.

Then, you are using it in useEffect but with [] as second parameter, that is, we are only calling loadData on componentDidMount.

Am I missing something?

Thank you.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cause I want to intentionally keep the same callback reference between re-renders. loadData does also serve as a handler for the button onClick.

trackPromise(getQuote(), "quote").then(setQuote);
trackPromise(getPicture(500, 200), "picture").then(setPicture);
}, []);

React.useEffect(() => loadData(), []);

return (
<div className={classes.container}>
<Button variant="outlined" onClick={loadData} className={classes.button}>Refresh</Button>
<Suspense tag="picture" className={classes.progress}>
<img src={picture} className={classes.pic}/>
</Suspense>
<Suspense tag="quote" className={classes.progress}>
<Typography variant="h4" align="center" className={classes.text}>{quote.body}</Typography>
<Typography variant="h5" className={classes.text}>{quote.author}</Typography>
</Suspense>
</div>
);
};

export const App = withStyles(styles)(AppInner);
14 changes: 14 additions & 0 deletions examples/06-suspense-like/src/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>React Promise Tracker - Suspense</title>
</head>

<body>
<div id="root"></div>
</body>

</html>
12 changes: 12 additions & 0 deletions examples/06-suspense-like/src/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import * as React from "react";
import * as ReactDOM from "react-dom";
import CssBaseline from "@material-ui/core/CssBaseline";
import { App } from "./app";

ReactDOM.render(
<>
<CssBaseline />
<App />
</>,
document.getElementById("root")
);
25 changes: 25 additions & 0 deletions examples/06-suspense-like/src/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { createStyles } from "@material-ui/core/styles";

export const styles = () => createStyles({
progress: {
margin: "1rem",
},
container: {
display: "flex",
flexDirection: "column",
alignItems: "center",
padding: "2rem",
},
button: {
marginBottom: "2rem",
},
pic: {
marginBottom: "1.25rem",
borderRadius: "8px",
},
text: {
marginBottom: "0.75rem",
}
});


16 changes: 16 additions & 0 deletions examples/06-suspense-like/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"compilerOptions": {
"target": "es6",
"module": "es6",
"moduleResolution": "node",
"declaration": false,
"noImplicitAny": false,
"jsx": "react",
"sourceMap": true,
"noLib": false,
"suppressImplicitAnyIndexErrors": true,
"allowSyntheticDefaultImports": true,
},
"compileOnSave": false,
"exclude": ["node_modules"]
}
92 changes: 92 additions & 0 deletions examples/06-suspense-like/tslint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
{
"extends": ["tslint:recommended", "tslint-react", "tslint-config-prettier"],
"defaultSeverity": "warning",
"rules": {
"align": [true, "parameters", "statements"],
"array-type": false,
"arrow-parens": false,
"class-name": true,
"comment-format": [true, "check-space"],
"curly": false,
"eofline": true,
"forin": false,
"import-spacing": true,
"indent": [true, "spaces"],
"interface-name": [true, "never-prefix"],
"jsdoc-format": true,
"jsx-no-lambda": false,
"jsx-no-multiline-js": false,
"label-position": true,
"max-line-length": [true, 120],
"member-ordering": false,
"member-access": false,
"no-any": false,
"no-arg": true,
"no-bitwise": true,
"no-console": false,
"no-consecutive-blank-lines": [true, 2],
"no-construct": true,
"no-debugger": true,
"no-default-export": false,
"no-duplicate-variable": true,
"no-empty": true,
"no-empty-interface": false,
"no-eval": true,
"no-implicit-dependencies": false,
"no-internal-module": true,
"no-object-literal-type-assertion": false,
"no-shadowed-variable": true,
"no-string-literal": false,
"no-submodule-imports": false,
"no-trailing-whitespace": true,
"no-unsafe-finally": true,
"no-unused-expression": true,
"no-var-keyword": true,
"no-var-requires": false,
"object-literal-key-quotes": [true, "as-needed"],
"object-literal-sort-keys": false,
"one-line": [true, "check-catch", "check-else", "check-open-brace", "check-whitespace"],
"only-arrow-functions": false,
"ordered-imports": false,
"quotemark": [true, "double", "jsx-double"],
"radix": false,
"semicolon": [true, "always", "strict-bound-class-methods"],
"trailing-comma": [
true,
{
"multiline": {
"objects": "always",
"arrays": "always",
"imports": "always",
"exports": "always",
"typeLiterals": "always"
},
"singleline": "never",
"esSpecCompliant": true
}
],
"triple-equals": [true, "allow-null-check"],
"typedef": [true, "parameter", "property-declaration"],
"typedef-whitespace": [
true,
{
"call-signature": "nospace",
"index-signature": "nospace",
"parameter": "nospace",
"property-declaration": "nospace",
"variable-declaration": "nospace"
}
],
"variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore", "allow-pascal-case"],
"whitespace": [
true,
"check-branch",
"check-decl",
"check-module",
"check-operator",
"check-separator",
"check-type",
"check-typecast"
]
}
}
41 changes: 41 additions & 0 deletions examples/06-suspense-like/webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
const HtmlWebpackPlugin = require("html-webpack-plugin");
const path = require("path");

const basePath = __dirname;

module.exports = {
context: path.join(basePath, "src"),
resolve: {
extensions: [".js", ".ts", ".tsx"],
},
entry: ["./index.tsx"],
output: {
path: path.join(basePath, "dist"),
filename: "bundle.js"
},
devtool: "source-map",
devServer: {
contentBase: "./dist", // Content base
inline: true, // Enable watch and live reload
host: "localhost",
port: 8080,
stats: "errors-only"
},
module: {
rules: [
{
test: /\.(tsx?)|(js)$/,
exclude: /node_modules/,
loader: "babel-loader",
},
]
},
plugins: [
//Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin
new HtmlWebpackPlugin({
filename: "index.html", //Name of file in ./dist/
template: "index.html", //Name of template in ./src
hash: true
})
]
};
16 changes: 16 additions & 0 deletions examples/07-suspense-custom/.babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "usage"
}
],
"@babel/preset-typescript",
"@babel/preset-react"
],
"plugins": [
"@babel/proposal-class-properties",
"@babel/proposal-object-rest-spread"
]
}
Loading