Skip to content

Commit

Permalink
change to object state and useReducer
Browse files Browse the repository at this point in the history
  • Loading branch information
dai-shi committed Feb 5, 2022
1 parent fbe2e03 commit f859b9c
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 25 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ store.prefetch('1');
// The `refetch` function take the input argument,
// and it will start fetching before rendering.
const Main = () => {
const [result, refetch] = useFetch(store, '1');
const { result, refetch } = useFetch(store, '1');
const handleClick = () => {
refetch('2');
};
Expand Down Expand Up @@ -116,7 +116,7 @@ useFetch hook
```javascript
import { useFetch } from 'react-hooks-fetch';

const [result, refetch] = useFetch(store, initialInput);
const { result, refetch } = useFetch(store, initialInput);
```

## Examples
Expand Down
2 changes: 1 addition & 1 deletion __tests__/01_basic_spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ describe('basic spec', () => {
store.prefetch(initialUrl);

const DisplayData = () => {
const [result] = useFetch(store, initialUrl);
const { result } = useFetch(store, initialUrl);
expect(result).toBe(responses[initialUrl]);
return <span>{result}</span>;
};
Expand Down
2 changes: 1 addition & 1 deletion examples/01_minimal/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const DisplayData = ({ result, refetch }) => {
};

const Main = () => {
const [result, refetch] = useFetch(store, '1');
const { result, refetch } = useFetch(store, '1');
return <DisplayData result={result} refetch={refetch} />;
};

Expand Down
4 changes: 2 additions & 2 deletions examples/02_typescript/src/Item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import DisplayData from './DisplayData';

const Item: React.FC = () => {
const [id, setId] = useState('1');
const [result, refetch] = useFetch(store, '1' as string);
const { result, refetch } = useFetch(store, '1' as string);
return (
<div>
User ID: <input value={id} onChange={(e) => setId(e.target.value)} />
Expand All @@ -17,7 +17,7 @@ const Item: React.FC = () => {
};

export const ErrorItem: React.FC = () => {
const [result, refetch] = useFetch(store, '1' as string);
const { result, refetch } = useFetch(store, '1' as string);
return (
<div>
<DisplayData id="-1" result={result} refetch={refetch} />
Expand Down
2 changes: 1 addition & 1 deletion examples/03_noinit/src/Item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type Props = {

const Item: React.FC<Props> = ({ initialId }) => {
const [id, setId] = useState(initialId);
const [result, refetch] = useFetch(store, initialId);
const { result, refetch } = useFetch(store, initialId);
return (
<div>
User ID: <input value={id || ''} onChange={(e) => setId(e.target.value)} />
Expand Down
93 changes: 75 additions & 18 deletions src/useFetch.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,103 @@
import { useCallback, useEffect, useState } from 'react';
import {
Dispatch,
Reducer,
useEffect,
useReducer,
} from 'react';

import { FetchStore } from './createFetch';

type Refetch<Input> = (input: Input) => void;

type State<Input, Result> = {
store: FetchStore<Input, Result>;
input: Input | undefined;
result: Result | undefined;
refetch: Refetch<Input>;
};

const initializeState = <Input, Result>(
store: FetchStore<Input, Result>,
initialInput: Input | undefined,
dispatch: Dispatch<{ type: 'NEW_INPUT', input: Input }>,
) => ({
store,
input: initialInput,
result: initialInput === undefined ? undefined : store.getResult(initialInput),
refetch: (nextInput: Input) => {
store.prefetch(nextInput);
dispatch({ type: 'NEW_INPUT', input: nextInput });
},
});

export function useFetch<Input, Result>(
store: FetchStore<Input, Result>,
initialInput: Input,
): [undefined extends Input ? Result | undefined : Result, Refetch<Input>];
): {
input: Input;
result: undefined extends Input ? Result | undefined : Result;
refetch: Refetch<Input>;
};

export function useFetch<Input, Result>(
store: FetchStore<Input, Result>,
initialInput?: Input,
): [Result | undefined, Refetch<Input>];
): {
input: Input | undefined;
result: Result | undefined;
refetch: Refetch<Input>;
};

/**
* useFetch hook
*
* @example
* import { useFetch } from 'react-hooks-fetch';
*
* const [result, refetch] = useFetch(store, initialInput);
* const { result, refetch } = useFetch(store, initialInput);
*/
export function useFetch<Input, Result>(
store: FetchStore<Input, Result>,
initialInput?: Input,
) {
const [input, setInput] = useState(initialInput);
const [result, setResult] = useState(() => {
if (initialInput === undefined) return undefined;
return store.getResult(initialInput);
});
type Action = { type: 'NEW_STORE' } | { type: 'NEW_INPUT', input: Input };
const [state, dispatch] = useReducer<
Reducer<State<Input, Result>, Action>,
undefined
>(
(prev, action): State<Input, Result> => {
if (action.type === 'NEW_STORE') {
if (prev.store === store) {
// not changed
return prev;
}
return initializeState(store, initialInput, (a: Action) => dispatch(a));
}
if (action.type === 'NEW_INPUT') {
return {
...prev,
input: action.input,
result: store.getResult(action.input),
};
}
return prev;
},
undefined,
(): State<Input, Result> => initializeState(
store,
initialInput,
(a: Action) => dispatch(a),
),
);
useEffect(() => {
dispatch({ type: 'NEW_STORE' });
}, [store]);
const { input } = state;
useEffect(() => {
if (input !== undefined) {
return store.use(input);
if (input === undefined) {
return undefined;
}
return undefined;
return store.use(input);
}, [store, input]);
const refetch = useCallback((nextInput: Input) => {
store.prefetch(nextInput);
setInput(nextInput);
setResult(() => store.getResult(nextInput));
}, [store]);
return [result, refetch];
return state;
}

0 comments on commit f859b9c

Please sign in to comment.