Skip to content

Commit

Permalink
exp: add and experimental reset action helper for atomWithValidate
Browse files Browse the repository at this point in the history
  • Loading branch information
barelyhuman committed May 30, 2024
1 parent 98d5caa commit 95527de
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 2 deletions.
45 changes: 45 additions & 0 deletions __tests__/01_basic_spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { fireEvent, render, waitFor } from '@testing-library/react';
import React from 'react';
import { useAtom } from 'jotai/react';
import { atomWithValidate } from '../src/index';
import { Constants } from '../src/atomWithValidate';

describe('atomWithValidate spec', () => {
it('only number', async () => {
Expand Down Expand Up @@ -53,4 +54,48 @@ describe('atomWithValidate spec', () => {
getByText('isValid: false');
});
});

it('reset value', async () => {
const dataAtom = atomWithValidate(0, {
validate: (v) => v,
});
const Component = () => {
const [{ value, isDirty }, setValue] = useAtom(dataAtom);
return (
<>
<div>value: {value}</div>
<div>isDirty: {JSON.stringify(isDirty)}</div>
<button
type="button"
onClick={() =>
// @ts-expect-error TODO TYPES
setValue({
[Constants.ACTION]: Constants.ACTION_RESET,
[Constants.VALUE]: 1,
})
}
>
reset
</button>
</>
);
};

const { getByText } = render(
<div>
<Component />
</div>,
);

await waitFor(() => {
getByText('value: 0');
getByText('isDirty: false');
});

fireEvent.click(getByText('reset'));
await waitFor(() => {
getByText('value: 1');
getByText('isDirty: false');
});
});
});
26 changes: 25 additions & 1 deletion src/atomWithValidate.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { atom } from 'jotai/vanilla';
import type { WritableAtom, SetStateAction } from 'jotai/vanilla';

export const Constants = {
ACTION: Symbol.for('ACTION'),
ACTION_RESET: Symbol.for('RESET'),
VALUE: Symbol.for('VALUE'),
};

export type CommonState<Value> = {
value: Value;
isDirty: boolean;
Expand Down Expand Up @@ -102,10 +108,28 @@ export function atomWithValidate<Value>(
(get) => get(baseAtom),
(get, set, action: SetStateAction<Value>) => {
const prevState = get(baseAtom);
const nextValue =
let toPerform: string | symbol | undefined;
let valueReader =
typeof action === 'function'
? (action as any)(prevState.value)
: action;

if (valueReader[Constants.ACTION]) {
toPerform = valueReader[Constants.ACTION];
valueReader = valueReader[Constants.VALUE];
}

const nextValue = valueReader;

if (toPerform === Constants.ACTION_RESET) {
set(baseAtom, {
value: nextValue,
isDirty: false,
isValid: true,
});
return;
}

try {
const validatedValue = validate(nextValue);
if (validatedValue instanceof Promise) {
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export { atomWithValidate } from './atomWithValidate';
export { Constants, atomWithValidate } from './atomWithValidate';
export { validateAtoms } from './validateAtoms';
export { atomWithFormControls } from './atomWithFormControls';

Expand Down

0 comments on commit 95527de

Please sign in to comment.