diff --git a/.gitignore b/.gitignore index 7bca893d..67a1d7cb 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ lerna-debug.log* # when working with contributors package-lock.json yarn.lock + +.vercel diff --git a/docs/api/options.md b/docs/api/options.md index 6ca6ac61..64d353e9 100644 --- a/docs/api/options.md +++ b/docs/api/options.md @@ -41,7 +41,7 @@ A function that returns a promise. It is automatically invoked in `componentDidM > `function(args: any[], props: Object, controller: AbortController): Promise` -A function that returns a promise. This is invoked only by manually calling `run(...args)`. Receives the same arguments as `promiseFn`, as well as any arguments to `run` which are passed through as an array. The `deferFn` is commonly used to send data to the server following a user action, such as submitting a form. You can use this in conjunction with `promiseFn` to fill the form with existing data, then updating it on submit with `deferFn`. +A function that returns a promise. This is invoked only by manually calling `run(...args)`. Any arguments to `run` are passed-through as an array via `args`, so you can pass data through either `args` or `props`, as needed. The `deferFn` is commonly used to send data to the server following a user action, such as submitting a form. You can use this in conjunction with `promiseFn` to fill the form with existing data, then updating it on submit with `deferFn`. > Be aware that when using both `promiseFn` and `deferFn`, the shape of their fulfilled value should match, because they both update the same `data`. @@ -87,7 +87,7 @@ Callback function invoked when a promise is cancelled, either manually using `ca > `function(state: any, action: Object, internalReducer: function(state: any, action: Object))` -State reducer to take full control over state updates by wrapping the [internal reducer](https://github.com/async-library/react-async/blob/master/src/reducer.js). It receives the current state, the dispatched action and the internal reducer. You probably want to invoke the internal reducer at some point. +State reducer to take full control over state updates by wrapping the [internal reducer](https://github.com/async-library/react-async/blob/master/packages/react-async/src/reducer.ts). It receives the current state, the dispatched action and the internal reducer. You probably want to invoke the internal reducer at some point. > This is a power feature which loosely follows the [state reducer pattern](https://kentcdodds.com/blog/the-state-reducer-pattern). It allows you to control state changes by intercepting actions before they are handled, or by overriding or enhancing the reducer itself. diff --git a/docs/introduction.md b/docs/introduction.md index 7b3e2879..2eb4c3e9 100644 --- a/docs/introduction.md +++ b/docs/introduction.md @@ -29,4 +29,4 @@ impact on performance and usability. When Suspense lands, React Async will make you can already **start using React Async right now**, and in a later update, you'll **get Suspense features for free**. In fact, React Async already has experimental support for Suspense, by passing the `suspense` option. -[concurrent react]: https://github.com/sw-yx/fresh-concurrent-react/blob/master/Intro.md#introduction-what-is-concurrent-react +[concurrent react]: https://reactjs.org/docs/concurrent-mode-intro.html diff --git a/package.json b/package.json index e2d06a47..2c69cc71 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "author": "Gert Hengeveld ", "license": "ISC", "homepage": "https://async-library.com", + "browserslist": "last 2 Firefox versions", "repository": "git+https://github.com/async-library/react-async.git", "workspaces": [ "examples/*", @@ -13,7 +14,7 @@ "bootstrap": "yarn build:packages && yarn workspaces run bootstrap", "clean": "lerna clean", "start": "run-p start:*", - "start:examples": "now dev", + "start:examples": "vercel dev", "start:storybook": "start-storybook -p 6006", "lint": "eslint packages/*/src/*.{js,ts,tsx}", "test": "jest packages/*/src/*.spec.js", @@ -25,24 +26,24 @@ "test:latest": "yarn add -D -W react@latest react-dom@latest && yarn resolutions:fix-react && yarn test", "test:compat": "yarn test:backwards && yarn test:forwards && yarn test:latest", "test:examples": "CI=1 lerna run --scope '*-example' test -- --passWithNoTests --watchAll=false", - "test:chromatic": "chromatic --app-code iiua39bmt0j --build-script-name build:storybook --exit-zero-on-changes", + "test:chromatic": "chromatic -t iiua39bmt0j -b build:storybook --exit-zero-on-changes", "resolutions:fix-react": "jq '.resolutions.react = .devDependencies.react|.resolutions.\"react-dom\"=.devDependencies.react' package.json > package.json.new && mv package.json.new package.json && yarn install", "ci": "yarn lint && yarn test:compat && yarn test:examples", "build:packages": "lerna run --scope 'react-async*' build", "build:examples": "lerna run --scope '*-example' build", "build:storybook": "build-storybook -o storybook", - "deploy:examples": "now --prod --scope async-library --token $NOW_API_TOKEN", + "deploy:examples": "vercel --prod --scope async-library --token $NOW_API_TOKEN", "bump": "lerna version -m 'Bump' --no-git-tag-version --no-push", "postbump": "yarn build:packages" }, "devDependencies": { - "@babel/core": "7.8.6", + "@babel/core": "7.9.6", "@babel/plugin-proposal-class-properties": "7.8.3", - "@babel/plugin-proposal-object-rest-spread": "7.8.3", - "@babel/plugin-transform-runtime": "7.8.3", - "@babel/preset-env": "7.8.7", - "@babel/preset-react": "7.8.3", - "@babel/preset-typescript": "7.8.3", + "@babel/plugin-proposal-object-rest-spread": "7.9.6", + "@babel/plugin-transform-runtime": "7.9.6", + "@babel/preset-env": "7.9.6", + "@babel/preset-react": "7.9.4", + "@babel/preset-typescript": "7.9.0", "@pika/pack": "0.5.0", "@pika/plugin-build-node": "0.9.2", "@pika/plugin-build-types": "0.9.2", @@ -51,36 +52,33 @@ "@pika/plugin-bundle-types": "0.9.2", "@pika/plugin-standard-pkg": "0.9.2", "@pika/plugin-ts-standard-pkg": "0.9.2", - "@storybook/react": "5.3.14", + "@storybook/react": "5.3.18", "@testing-library/jest-dom": "4.2.4", - "@testing-library/react": "9.4.1", - "@typescript-eslint/eslint-plugin": "2.22.0", - "@typescript-eslint/parser": "2.22.0", + "@testing-library/react": "9.5.0", + "@typescript-eslint/eslint-plugin": "2.33.0", + "@typescript-eslint/parser": "2.33.0", "babel-eslint": "10.1.0", "babel-jest": "24.9.0", - "babel-loader": "8.0.6", + "babel-loader": "8.1.0", + "chromatic": "5.2.0", "copyfiles": "2.2.0", "eslint": "6.8.0", - "eslint-config-prettier": "6.10.0", - "eslint-plugin-jest": "23.8.1", - "eslint-plugin-prettier": "3.1.2", + "eslint-config-prettier": "6.11.0", + "eslint-plugin-jest": "23.11.0", + "eslint-plugin-prettier": "3.1.3", "eslint-plugin-promise": "4.2.1", - "eslint-plugin-react": "7.18.3", - "eslint-plugin-react-hooks": "2.5.0", + "eslint-plugin-react": "7.19.0", + "eslint-plugin-react-hooks": "2.5.1", "jest": "24.9.0", "lerna": "3.20.2", - "node-jq": "1.11.0", - "now": "16.7.3", + "node-jq": "1.11.1", + "vercel": "20.1.2", "npm-run-all": "4.1.5", "prettier": "1.19.1", "prop-types": "15.7.2", - "react": "16.13.0", + "react": "17.0.2", "react-async": "10.0.0-alpha.0", - "react-dom": "16.13.0", - "storybook-chromatic": "3.5.2", + "react-dom": "17.0.2", "typescript": "3.8.3" - }, - "resolutions": { - "@types/react": "16.9.13" } } diff --git a/packages/react-async/src/globalScope.ts b/packages/react-async/src/globalScope.ts index 8fd3ffbd..91a0067e 100644 --- a/packages/react-async/src/globalScope.ts +++ b/packages/react-async/src/globalScope.ts @@ -11,9 +11,10 @@ declare type GlobalScope = { * This file is excluded from coverage reporting because these globals are environment-specific so we can't test them all. */ const globalScope = (() => { + const glbl = global as any if (typeof self === "object" && self.self === self) return self - if (typeof global === "object" && global.global === global) return global - if (typeof global === "object" && global.GLOBAL === global) return global + if (typeof glbl === "object" && glbl.global === glbl) return glbl + if (typeof glbl === "object" && glbl.GLOBAL === glbl) return glbl return {} // fallback that relies on imported modules to be singletons })() as GlobalScope diff --git a/packages/react-async/src/specs.js b/packages/react-async/src/specs.js index 14054789..3517f903 100644 --- a/packages/react-async/src/specs.js +++ b/packages/react-async/src/specs.js @@ -283,7 +283,7 @@ export const withPromiseFn = (Async, abortCtrl) => () => { expect(promiseFn).toHaveBeenCalledTimes(1) fireEvent.click(getByText("reload")) expect(promiseFn).toHaveBeenCalledTimes(2) - expect(abortCtrl.abort).toHaveBeenCalledTimes(1) + expect(abortCtrl.abort).toHaveBeenCalled() }) test("re-runs the promise with new props when the value of `watch` changes", () => { @@ -404,7 +404,7 @@ export const withPromiseFn = (Async, abortCtrl) => () => { rerender() await sleep(10) expect(onResolve).not.toHaveBeenCalled() - expect(abortCtrl.abort).toHaveBeenCalledTimes(1) + expect(abortCtrl.abort).toHaveBeenCalled() }) test("does not run `promiseFn` on mount when `initialValue` is provided", async () => { diff --git a/packages/react-async/src/useAsync.tsx b/packages/react-async/src/useAsync.tsx index b3eb22d9..291e3709 100644 --- a/packages/react-async/src/useAsync.tsx +++ b/packages/react-async/src/useAsync.tsx @@ -10,6 +10,7 @@ import { } from "./reducer" import { + AsyncAction, AsyncOptions, AsyncState, AbstractState, @@ -60,7 +61,9 @@ function useAsync(arg1: AsyncOptions | PromiseFn, arg2?: AsyncOptions reducer(state, action, asyncReducer) : asyncReducer, + reducer + ? (state: AsyncState, action: AsyncAction) => reducer(state, action, asyncReducer) + : asyncReducer, options, init ) @@ -336,5 +339,7 @@ const unsupported = () => { ) } +// @ts-ignore export default useEffect ? useAsync : unsupported +// @ts-ignore export const useFetch = useEffect ? useAsyncFetch : unsupported diff --git a/packages/react-async/tsconfig.json b/packages/react-async/tsconfig.json index f261ce40..89209d65 100644 --- a/packages/react-async/tsconfig.json +++ b/packages/react-async/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "es2019", + "target": "es2020", "module": "esnext", "allowJs": false, "checkJs": false, diff --git a/now.json b/vercel.json similarity index 100% rename from now.json rename to vercel.json