diff --git a/packages/react-async/src/specs.js b/packages/react-async/src/specs.js
index a5372e3e..46ad0dc6 100644
--- a/packages/react-async/src/specs.js
+++ b/packages/react-async/src/specs.js
@@ -397,6 +397,46 @@ export const withDeferFn = (Async, abortCtrl) => () => {
expect(deferFn).toHaveBeenCalledWith(["go", 2], expect.objectContaining(props), abortCtrl)
})
+ test("always passes the latest props", async () => {
+ const deferFn = jest.fn().mockReturnValue(resolveTo())
+ const Child = ({ count }) => (
+
+ {({ run }) => (
+ <>
+
+ {count}
+ >
+ )}
+
+ )
+ class Parent extends React.Component {
+ constructor(props) {
+ super(props)
+ this.state = { count: 0 }
+ }
+ render() {
+ const inc = () => this.setState(state => ({ count: state.count + 1 }))
+ return (
+ <>
+
+ {this.state.count && }
+ >
+ )
+ }
+ }
+ const { getByText, getByTestId } = render()
+ fireEvent.click(getByText("inc"))
+ expect(getByTestId("counter")).toHaveTextContent("1")
+ fireEvent.click(getByText("inc"))
+ expect(getByTestId("counter")).toHaveTextContent("2")
+ fireEvent.click(getByText("run"))
+ expect(deferFn).toHaveBeenCalledWith(
+ [2],
+ expect.objectContaining({ count: 2, deferFn }),
+ abortCtrl
+ )
+ })
+
test("`reload` uses the arguments of the previous run", () => {
let counter = 1
const deferFn = jest.fn().mockReturnValue(resolveTo())
diff --git a/packages/react-async/src/useAsync.js b/packages/react-async/src/useAsync.js
index b259d98a..b2281aac 100644
--- a/packages/react-async/src/useAsync.js
+++ b/packages/react-async/src/useAsync.js
@@ -11,7 +11,7 @@ const useAsync = (arg1, arg2) => {
const counter = useRef(0)
const isMounted = useRef(true)
const lastArgs = useRef(undefined)
- const prevOptions = useRef(undefined)
+ const lastOptions = useRef(undefined)
const abortController = useRef({ abort: noop })
const { devToolsDispatcher } = globalScope.__REACT_ASYNC__
@@ -72,7 +72,7 @@ const useAsync = (arg1, arg2) => {
}
const isPreInitialized = initialValue && counter.current === 0
if (promiseFn && !isPreInitialized) {
- return start(() => promiseFn(options, abortController.current)).then(
+ return start(() => promiseFn(lastOptions.current, abortController.current)).then(
handleResolve(counter.current),
handleReject(counter.current)
)
@@ -83,7 +83,7 @@ const useAsync = (arg1, arg2) => {
const run = (...args) => {
if (deferFn) {
lastArgs.current = args
- return start(() => deferFn(args, options, abortController.current)).then(
+ return start(() => deferFn(args, lastOptions.current, abortController.current)).then(
handleResolve(counter.current),
handleReject(counter.current)
)
@@ -99,15 +99,15 @@ const useAsync = (arg1, arg2) => {
const { watch, watchFn } = options
useEffect(() => {
- if (watchFn && prevOptions.current && watchFn(options, prevOptions.current)) load()
+ if (watchFn && lastOptions.current && watchFn(options, lastOptions.current)) load()
})
+ useEffect(() => (lastOptions.current = options) && undefined)
useEffect(() => {
if (counter.current) cancel()
if (promise || promiseFn) load()
}, [promise, promiseFn, watch])
useEffect(() => () => (isMounted.current = false), [])
useEffect(() => () => cancel(), [])
- useEffect(() => (prevOptions.current = options) && undefined)
useDebugValue(state, ({ status }) => `[${counter.current}] ${status}`)