Skip to content

Commit

Permalink
feat: optional fire on unmount (#15)
Browse files Browse the repository at this point in the history
* add ability to toggle save on unmount

* test changes

* update docs
  • Loading branch information
jollyjerr committed May 15, 2022
1 parent 23aa284 commit 3465e9a
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 19 deletions.
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,22 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.4.0] - 5-15-22

## Added

- A toggle to cancel saving on unmount `saveOnUnmount`
- The ability to save falsy values
- Dev page using vite to preview current build
- React 18 support

## Changed

- Package builds using vite
- Switched to PNPM
- Test run using vitest
- All dependencies bumped to latest version

## [0.3.1] - 12-21-21

## Added
Expand Down
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,16 @@ npm i react-autosave
| data | TData | The controlled form value to be auto saved |
| onSave | (data: TData) => any | The callback function to save your data |
| interval (optional) | number | The number of milliseconds between save attempts. Defaults to 2000 |
| saveOnUnmount (optional) | boolean | Defaults to true. Set to false to prevent saving on unmount |

### Contributing

Issues and PRs are more than welcome. Please clone the repo and setup your environment with:

```sh
yarn
pnpm
```

The test suite can be run with `yarn test`
The test suite can be run with `pnpm test`
Buid the library with `pnpm build`
A demo page can be viewed with `pnpm build && pnpm dev`
25 changes: 16 additions & 9 deletions example/App.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import React from 'react';
import React, { Dispatch, SetStateAction } from 'react';
import { useState } from 'react';
import { useAutosave } from '..';

function App() {
const [showForm, setShowForm] = useState(true);
const [text, setText] = useState('hello world');
const [value, setValue] = useState(text);

useAutosave({ data: text, onSave: setValue });

return (
<div
style={{
Expand All @@ -21,18 +20,26 @@ function App() {
padding: 16,
}}
>
<input
type="text"
data-testid="input"
value={text}
onChange={(e) => setText(e.target.value)}
/>
{showForm ? <Form setText={setText} text={text} setValue={setValue} /> : null}
<p>
Save function called with:{' '}
<span style={{ fontWeight: 'bold' }}>{value}</span>
</p>
<button onClick={() => setShowForm(prev => !prev)}>Toggle form</button>
</div>
);
}

const Form = ({text, setText, setValue}: {text: string, setText: Dispatch<SetStateAction<string>>, setValue: Dispatch<SetStateAction<string>>}) => {
useAutosave({ data: text, onSave: setValue });
return (
<input
type="text"
data-testid="input"
value={text}
onChange={(e) => setText(e.target.value)}
/>
);
};

export default App;
17 changes: 15 additions & 2 deletions src/Autosave.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ import Autosave from './Autosave';

type TestProps = {
onSave: (data: any) => Promise<any>;
saveOnUnmount?: boolean;
};
function TestComponent({ onSave }: TestProps) {
function TestComponent({ onSave, saveOnUnmount = true }: TestProps) {
const [data, setdata] = React.useState('hello world');
const [showForm, setShowForm] = React.useState(true);
return showForm ? (
Expand All @@ -19,7 +20,7 @@ function TestComponent({ onSave }: TestProps) {
value={data}
onChange={(e) => setdata(e.target.value)}
/>
<Autosave data={data} onSave={onSave} />
<Autosave data={data} onSave={onSave} saveOnUnmount={saveOnUnmount} />
<button
type="button"
data-testid="unmount"
Expand Down Expand Up @@ -90,4 +91,16 @@ describe('<Autosave />', () => {
expect(saveFunction).toHaveBeenCalledTimes(1);
vi.clearAllMocks();
});

it('Can toggle off saving when unmounted', async () => {
vi.useFakeTimers();
const user = userEvent.setup({advanceTimers: (time) => vi.advanceTimersByTime(time)});
const saveFunction = vi.fn();
render(<TestComponent onSave={saveFunction} saveOnUnmount={false} />);

await user.click(screen.getByTestId('unmount'));

expect(saveFunction).toHaveBeenCalledTimes(0);
vi.clearAllMocks();
});
});
6 changes: 2 additions & 4 deletions src/Autosave.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@ import { AutosaveProps } from './props';
import useAutosave from './useAutosave';

const Autosave = <TData, TReturn>({
data,
onSave,
interval = 2000,
element = null,
...props
}: AutosaveProps<TData, TReturn>) => {
useAutosave({ data, onSave, interval });
useAutosave(props);
return element;
};

Expand Down
2 changes: 2 additions & 0 deletions src/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ export interface CommonProps<TData, TReturn> {
onSave: (data: TData) => Promise<TReturn> | TReturn | void;
/** The number of milliseconds between save attempts. Defaults to 2000 */
interval?: number;
/** Set to false if you do not want the save function to fire on unmount */
saveOnUnmount?: boolean;
}

export interface AutosaveProps<TData, TReturn>
Expand Down
7 changes: 5 additions & 2 deletions src/useAutosave.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ function useAutosave<TData, TReturn>({
data,
onSave,
interval = 2000,
saveOnUnmount = true
}: CommonProps<TData, TReturn>) {
const valueOnCleanup = useRef(data);
const initialRender = useRef(true);
Expand All @@ -24,8 +25,10 @@ function useAutosave<TData, TReturn>({
}, [data]);

useEffect(() => () => {
onSave(valueOnCleanup.current);
}, [onSave]);
if (saveOnUnmount) {
onSave(valueOnCleanup.current);
}
}, [onSave, saveOnUnmount]);
}

export default useAutosave;

0 comments on commit 3465e9a

Please sign in to comment.