Skip to content

Commit

Permalink
Memoize mutation callbacks
Browse files Browse the repository at this point in the history
  • Loading branch information
rkfg committed Jan 11, 2023
1 parent 5f2001a commit 12b6f53
Show file tree
Hide file tree
Showing 8 changed files with 30 additions and 32 deletions.
3 changes: 2 additions & 1 deletion packages/ra-core/src/dataProvider/useCreate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {

import { useDataProvider } from './useDataProvider';
import { RaRecord, CreateParams } from '../types';
import { useEvent } from '../util';

/**
* Get a callback to call the dataProvider.create() method, the result and the loading state.
Expand Down Expand Up @@ -142,7 +143,7 @@ export const useCreate = <
);
};

return [create, mutation];
return [useEvent(create), mutation];
};

export interface UseCreateMutateParams<RecordType extends RaRecord = any> {
Expand Down
3 changes: 2 additions & 1 deletion packages/ra-core/src/dataProvider/useDelete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
MutationMode,
GetListResult as OriginalGetListResult,
} from '../types';
import { useEvent } from '../util';

/**
* Get a callback to call the dataProvider.delete() method, the result and the loading state.
Expand Down Expand Up @@ -387,7 +388,7 @@ export const useDelete = <
}
};

return [mutate, mutation];
return [useEvent(mutate), mutation];
};

type Snapshot = [key: QueryKey, value: any][];
Expand Down
3 changes: 2 additions & 1 deletion packages/ra-core/src/dataProvider/useDeleteMany.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
MutationMode,
GetListResult as OriginalGetListResult,
} from '../types';
import { useEvent } from '../util';

/**
* Get a callback to call the dataProvider.delete() method, the result and the loading state.
Expand Down Expand Up @@ -394,7 +395,7 @@ export const useDeleteMany = <
}
};

return [mutate, mutation];
return [useEvent(mutate), mutation];
};

type Snapshot = [key: QueryKey, value: any][];
Expand Down
3 changes: 2 additions & 1 deletion packages/ra-core/src/dataProvider/useUpdate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
MutationMode,
GetListResult as OriginalGetListResult,
} from '../types';
import { useEvent } from '../util';

/**
* Get a callback to call the dataProvider.update() method, the result and the loading state.
Expand Down Expand Up @@ -418,7 +419,7 @@ export const useUpdate = <
}
};

return [update, mutation];
return [useEvent(update), mutation];
};

type Snapshot = [key: QueryKey, value: any][];
Expand Down
3 changes: 2 additions & 1 deletion packages/ra-core/src/dataProvider/useUpdateMany.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
MutationMode,
GetListResult as OriginalGetListResult,
} from '../types';
import { useEvent } from '../util';
import { Identifier } from '..';

/**
Expand Down Expand Up @@ -420,7 +421,7 @@ export const useUpdateMany = <
}
};

return [updateMany, mutation];
return [useEvent(updateMany), mutation];
};

type Snapshot = [key: QueryKey, value: any][];
Expand Down
37 changes: 16 additions & 21 deletions packages/ra-core/src/store/useStore.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useState, useEffect } from 'react';
import isEqual from 'lodash/isEqual';

import { useEventCallback } from '../util';
import { useEvent } from '../util';
import { useStoreContext } from './useStoreContext';

/**
Expand Down Expand Up @@ -64,26 +64,21 @@ export const useStore = <T = any>(
return () => unsubscribe();
}, [key, subscribe, defaultValue, getItem, value]);

const set = useEventCallback(
(valueParam: T, runtimeDefaultValue: T) => {
const newValue =
typeof valueParam === 'function'
? valueParam(value)
: valueParam;
// we only set the value in the Store;
// the value in the local state will be updated
// by the useEffect during the next render
setItem(
key,
typeof newValue === 'undefined'
? typeof runtimeDefaultValue === 'undefined'
? defaultValue
: runtimeDefaultValue
: newValue
);
},
[key, setItem, defaultValue, value]
);
const set = useEvent((valueParam: T, runtimeDefaultValue: T) => {
const newValue =
typeof valueParam === 'function' ? valueParam(value) : valueParam;
// we only set the value in the Store;
// the value in the local state will be updated
// by the useEffect during the next render
setItem(
key,
typeof newValue === 'undefined'
? typeof runtimeDefaultValue === 'undefined'
? defaultValue
: runtimeDefaultValue
: newValue
);
});
return [value, set];
};

Expand Down
2 changes: 1 addition & 1 deletion packages/ra-core/src/util/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import warning from './warning';
import useWhyDidYouUpdate from './useWhyDidYouUpdate';
import { getMutationMode } from './getMutationMode';
export * from './mergeRefs';
export * from './useEventCallback';
export * from './useEvent';

export {
escapePath,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,16 @@ const useLayoutEffect =
* @see https://reactjs.org/docs/hooks-faq.html#how-to-read-an-often-changing-value-from-usecallback
* @see https://github.com/facebook/react/issues/14099#issuecomment-440013892
*/
export const useEventCallback = <Args extends unknown[], Return>(
fn: (...args: Args) => Return,
dependencies: any[]
export const useEvent = <Args extends unknown[], Return>(
fn: (...args: Args) => Return
): ((...args: Args) => Return) => {
const ref = React.useRef<(...args: Args) => Return>(() => {
throw new Error('Cannot call an event handler while rendering.');
});

useLayoutEffect(() => {
ref.current = fn;
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [fn, ...dependencies]);
});

return useCallback((...args: Args) => ref.current(...args), []);
};

0 comments on commit 12b6f53

Please sign in to comment.