Skip to content

Commit

Permalink
useFetch: allow passing an object to run to be spread over init
Browse files Browse the repository at this point in the history
  • Loading branch information
phryneas committed Aug 15, 2019
1 parent ec58f61 commit bae616c
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 4 deletions.
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,19 @@ const MyComponent = () => {
function clickHandler() {
run(init => ({
...init,
body: JSON.stringify(formValues)
headers: {
...init.headers,
authentication: "..."
}
}))
}

// alternatively, you can also just use an object that will be spread over `init`.
// please note that this is not deep-merged, so you might override properties present in the
// original `init` parameter
function clickHandler2() {
run({ body: JSON.stringify(formValues) })
}
}
```

Expand Down
13 changes: 11 additions & 2 deletions packages/react-async/src/useAsync.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useCallback, useDebugValue, useEffect, useMemo, useRef, useReducer } fr
import globalScope from "./globalScope"
import { actionTypes, init, dispatchMiddleware, reducer as asyncReducer } from "./reducer"

const noop = () => {}
const noop = () => { }

const useAsync = (arg1, arg2) => {
const options = typeof arg1 === "function" ? { ...arg2, promiseFn: arg1 } : arg1
Expand Down Expand Up @@ -143,7 +143,16 @@ const useAsyncFetch = (input, init, { defer, json, ...options } = {}) => {
[fn]: useCallback(
isDefer
? ([override], _, { signal }) =>
doFetch(input, { signal, ...(typeof override === "function" ? override(init) : init) })
doFetch(input, {
signal, ...(
// override is a function, call it with init
typeof override === "function" ? override(init)
// override is an Event or SyntheticEvent - do not spread
: 'preventDefault' in override ? init
// otherwise, spread override over init
: { ...init, ...override }
)
})
: (_, { signal }) => doFetch(input, { signal, ...init }),
[isDefer, JSON.stringify(input), JSON.stringify(init)]
),
Expand Down
40 changes: 39 additions & 1 deletion packages/react-async/src/useAsync.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ describe("useFetch", () => {
expect(json).toHaveBeenCalled()
})

test("calling `run` with an argument allows to override `init` parameters", () => {
test("calling `run` with a method argument allows to override `init` parameters", () => {
const component = (
<Fetch input="/test" init={{ method: "POST" }}>
{({ run }) => (
Expand All @@ -178,4 +178,42 @@ describe("useFetch", () => {
expect.objectContaining({ method: "POST", signal: abortCtrl.signal, body: '{"name":"test"}' })
)
})


test("calling `run` with an object as argument allows to override `init` parameters", () => {
const component = (
<Fetch input="/test" init={{ method: "POST" }}>
{({ run }) => (
<button onClick={() => run({ body: '{"name":"test"}' })}>run</button>
)}
</Fetch>
)
const { getByText } = render(component)
expect(globalScope.fetch).not.toHaveBeenCalled()
fireEvent.click(getByText("run"))
expect(globalScope.fetch).toHaveBeenCalledWith(
"/test",
expect.objectContaining({ method: "POST", signal: abortCtrl.signal, body: '{"name":"test"}' })
)
})


test("passing `run` directly as a click handler will not spread the event over init", () => {
const component = (
<Fetch input="/test" init={{ method: "POST" }}>
{({ run }) => (<button onClick={run}>run</button>)}
</Fetch >
)
const { getByText } = render(component)
expect(globalScope.fetch).not.toHaveBeenCalled()
fireEvent.click(getByText("run"))
expect(globalScope.fetch).toHaveBeenCalledWith(
"/test",
expect.any(Object)
);
expect(globalScope.fetch).not.toHaveBeenCalledWith(
"/test",
expect.objectContaining({ preventDefault: expect.any(Function) })
)
})
})

0 comments on commit bae616c

Please sign in to comment.