@applica-software-guru/react-admin 1.3.165 → 1.3.167

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/ApplicaAdmin.d.ts +43 -36
  2. package/dist/ApplicaAdmin.d.ts.map +1 -1
  3. package/dist/components/AuthWrapper.d.ts +20 -17
  4. package/dist/components/AuthWrapper.d.ts.map +1 -1
  5. package/dist/components/Layout/Navigation/NavGroup.d.ts.map +1 -1
  6. package/dist/components/MainIcon.d.ts +4 -9
  7. package/dist/components/MainIcon.d.ts.map +1 -1
  8. package/dist/components/ra-pages/ActivatePage.d.ts +1 -1
  9. package/dist/components/ra-pages/ActivatePage.d.ts.map +1 -1
  10. package/dist/components/ra-pages/LoginPage.d.ts +11 -11
  11. package/dist/components/ra-pages/LoginPage.d.ts.map +1 -1
  12. package/dist/components/ra-pages/RecoverPage.d.ts +1 -1
  13. package/dist/components/ra-pages/RecoverPage.d.ts.map +1 -1
  14. package/dist/components/ra-pages/RegisterPage.d.ts +1 -1
  15. package/dist/components/ra-pages/RegisterPage.d.ts.map +1 -1
  16. package/dist/components/ra-pages/types.d.ts +8 -5
  17. package/dist/components/ra-pages/types.d.ts.map +1 -1
  18. package/dist/hooks/useLocalStorage.d.ts.map +1 -1
  19. package/dist/react-admin.cjs.js +62 -62
  20. package/dist/react-admin.cjs.js.map +1 -1
  21. package/dist/react-admin.es.js +5028 -5032
  22. package/dist/react-admin.es.js.map +1 -1
  23. package/dist/react-admin.umd.js +62 -62
  24. package/dist/react-admin.umd.js.map +1 -1
  25. package/package.json +1 -1
  26. package/src/ApplicaAdmin.tsx +46 -36
  27. package/src/components/{AuthWrapper.jsx → AuthWrapper.tsx} +13 -4
  28. package/src/components/Layout/Navigation/NavGroup.jsx +1 -2
  29. package/src/components/{MainIcon.jsx → MainIcon.tsx} +4 -8
  30. package/src/components/ra-pages/ActivatePage.tsx +2 -2
  31. package/src/components/ra-pages/LoginPage.tsx +12 -12
  32. package/src/components/ra-pages/RecoverPage.tsx +2 -2
  33. package/src/components/ra-pages/RegisterPage.tsx +2 -2
  34. package/src/components/ra-pages/types.ts +8 -5
  35. package/src/hooks/useLocalStorage.tsx +25 -28
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applica-software-guru/react-admin",
3
- "version": "1.3.165",
3
+ "version": "1.3.167",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",
@@ -21,98 +21,98 @@ const defaultQueryClient = new QueryClient({
21
21
 
22
22
  export type ApplicaAdminProps = AdminProps & {
23
23
  /**
24
- * Eventuali configurazioni aggiuntive da passare al tema.
25
- * @remarks Questo tema è basato su Mantis Theme (https://mantisdashboard.io/)
24
+ * Optionally, a custom theme to use in the application.
25
+ * @remarks This theme is based on Mantis Theme (https://mantisdashboard.io/)
26
26
  *
27
27
  * @see https://marmelab.com/react-admin/Theming.html
28
28
  * @see https://material-ui.com/customization/theming/
29
29
  */
30
30
  theme: any;
31
31
  /**
32
- * Consente di personalizzare ulteriormente il tema in base alle specifiche esposte dal tema stesso.
33
- * Divertiti con cautela a modificare variabili di configurazione del tema, se fai un casino Marco Colucci potrebbe usare l'estintore (ho detto tutto).
32
+ * Optionally, a custom theme configuration to use in the application.
33
+ * Have fun with caution to modify theme configuration variables, if you make a mess Marco Colucci could use the fire extinguisher (I said everything).
34
34
  */
35
35
  themeConfig: ThemeConfig;
36
36
  /**
37
- * URL dell'API da utilizzare nell'applicazione.
38
- * Sebbene venga già definito un dataProvider ed authProvider di default, è possibile che l'app
39
- * utilizzi l'apiUrl specificato per ulteriori operazioni (es. getstione delle notifiche).
37
+ * The URL of the API to use in the application.
38
+ * Although a default dataProvider and authProvider are already defined, it is possible that the app
39
+ * uses the specified apiUrl for further operations (e.g. handling notifications).
40
40
  */
41
41
  apiUrl: string;
42
42
  /**
43
- * La lingua di default da utilizzare nell'applicazione.
43
+ * The default language to use in the application (default: en).
44
44
  */
45
45
  defaultLocale: string;
46
46
  /**
47
- * Se impostato a true, l'applicazione lavora in modalità sviluppo.
48
- * La modalità sviluppo è utile per effettuare test e debug ed esegue attività che non sono
49
- * consigliate in produzione (es. cattura e inoltro dei messaggi non localizzati).
47
+ * If set to true, the application works in development mode.
48
+ * Development mode is useful for testing and debugging and performs activities that are not
49
+ * recommended in production (e.g. capturing and forwarding non-localized messages).
50
50
  */
51
51
  development: boolean;
52
52
  /**
53
- * Il logo da visualizzare nella barra laterale quando il menu è espanso lateralmente.
53
+ * The main logo to display in the sidebar when the menu is expanded laterally.
54
54
  */
55
55
  logoMain: any;
56
56
  /**
57
- * Eventuale logo da visualizzare nella barra laterale quando il menu è ridotto lateralmente.
57
+ * The icon to display in the sidebar when the menu is collapsed laterally.
58
58
  */
59
59
  logoIcon: any;
60
60
  /**
61
- * Configurazione del menu da visualizzare nell'applicazione.
61
+ * Configured menu to display in the application.
62
62
  */
63
63
  menu: MenuProps;
64
64
  /**
65
- * Nome dell'applicazione da mostrare nell'header.
65
+ * The name of the application to display in the header.
66
66
  */
67
67
  name: string;
68
68
  /**
69
- * Testo da mostrare nel footer. Default: '© Applica Software Guru for'.
69
+ * Text to display in the footer. Default: '© Applica Software Guru for'.
70
70
  */
71
71
  copy: string;
72
72
  /**
73
- * Versione dell'applicazione da mostrare nel footer.
73
+ * Application version to display in the footer.
74
74
  */
75
75
  version: string;
76
76
  /**
77
- * Il provider di autenticazione da utilizzare nell'applicazione.
77
+ * The data provider to use in the application.
78
78
  */
79
79
  dataProvider: DataProvider;
80
80
  /**
81
- * Il provider di dati da utilizzare nell'applicazione.
81
+ * The auth provider to use in the application.
82
82
  */
83
83
  authProvider: AuthProvider;
84
84
  /**
85
- * Indica l'eventuale handler da utilizzare per la gestione degli errori.
86
- * Di default è eseguita una chiamata PUT /api/ui/error con il messaggio di errore "error".
87
- * Puoi implementare un tuo handler per gestire gli errori in modo diverso.
85
+ * Indicates the handler to use for error management.
86
+ * By default, a PUT /api/ui/error call is made with the error message "error".
87
+ * You can implement your own handler to manage errors differently.
88
88
  */
89
89
  errorHandler?: IErrorEventHandler | undefined;
90
90
  /**
91
- * Indica il componente da visualizzare in caso di errore.
91
+ * Indicates the component to display in case of error.
92
92
  */
93
93
  error: React.Component;
94
94
  /**
95
- * Indica il nome della risorsa REST da utilizzare per la gestione delle notifiche.
95
+ * Indicates the name of the REST resource to use for notification management.
96
96
  * @default "entities/notification"
97
97
  * @example
98
- * // In questo caso, le notifiche verranno gestite tramite la risorsa "entities/notification"
98
+ * // In this case, notifications will be managed through the "entities/notification" resource
99
99
  * <ApplicaAdmin notification="entities/notification" />
100
100
  */
101
101
  notification: string;
102
102
  /**
103
- * Indica se le notifiche devono essere disabilitate.
104
- * Se le notifiche sono abilitate comparirà automaticamente un'icona in alto a destra nell'header.
103
+ * Indicates whether notifications should be disabled.
104
+ * If notifications are enabled, an icon will automatically appear in the top right of the header.
105
105
  *
106
106
  * @example
107
107
  * <ApplicaAdmin enableNotification />
108
108
  */
109
109
  enableNotification: boolean;
110
110
  /**
111
- * Indica se la schermata di registrazione deve essere disabilitata.
112
- * Se abilitata è necessario registrare una pagina, nelle rotte, che punti a /register
111
+ * Indicates whether the registration screen should be disabled.
112
+ * If enabled, it is necessary to register a page, in the routes, that points to /register
113
113
  *
114
114
  * @example
115
- * // Pagina di base realizzata da Applica
115
+ * // Basic page made by Applica
116
116
  * import { RegisterPage } from "@applica-software-guru/react-admin";
117
117
  * <CustomRoutes noLayout>
118
118
  * <Route path="/register" component={RegisterPage} />
@@ -120,11 +120,11 @@ export type ApplicaAdminProps = AdminProps & {
120
120
  */
121
121
  enableRegistration: boolean;
122
122
  /**
123
- * Indica se la schermata di recupero password deve essere disabilitata.
124
- * Se abilitata è necessario registrare una pagina, nelle rotte, che punti a /recover
123
+ * Indicates whether the password recovery screen should be disabled.
124
+ * If enabled, it is necessary to register a page, in the routes, that points to /recover
125
125
  *
126
126
  * @example
127
- * // Pagina di base realizzata da Applica
127
+ * // Basic page made by Applica
128
128
  * import { RecoverPage } from "@applica-software-guru/react-admin";
129
129
  * <CustomRoutes noLayout>
130
130
  * <Route path="/recover" component={RecoverPage} />
@@ -132,13 +132,20 @@ export type ApplicaAdminProps = AdminProps & {
132
132
  */
133
133
  enablePasswordRecover: boolean;
134
134
  /**
135
- * L'instanza di QueryClient da utilizzare nell'applicazione
135
+ * The query client instance to use in the application.
136
136
  */
137
137
  queryClient: QueryClient;
138
+ /**
139
+ * Background image to display in login, recover, and register pages.
140
+ * This image must be a component with absolute positioning.
141
+ */
142
+ background?: React.ReactNode;
138
143
  };
139
144
 
140
145
  /**
141
- * Definisce un'applicazione super figa basata su React Admin, Mantis Theme ed il nostro stile.
146
+ * Define a basic super cool application based on React Admin, Mantis Theme and our style.
147
+ *
148
+ * @author A-Team - The Applica Software Guru
142
149
  * @param {ApplicaAdminProps}
143
150
  * @returns {React.ReactElement}
144
151
  */
@@ -164,6 +171,7 @@ const ApplicaAdmin = ({
164
171
  enableRegistration,
165
172
  enablePasswordRecover,
166
173
  queryClient,
174
+ background,
167
175
  ...props
168
176
  }: ApplicaAdminProps) => {
169
177
  useErrorEventCatcher({
@@ -196,13 +204,15 @@ const ApplicaAdmin = ({
196
204
  // @ts-ignore
197
205
  name,
198
206
  copy,
207
+ logo: logoMain,
199
208
  version,
209
+ background,
200
210
  enableRegistration,
201
211
  enablePasswordRecover
202
212
  });
203
213
  }
204
214
  return loginPage;
205
- }, [loginPage, name, version, copy, enableRegistration, enablePasswordRecover]);
215
+ }, [loginPage, name, version, copy, background, logoMain, enableRegistration, enablePasswordRecover]);
206
216
  const layout = useMemo(
207
217
  () => (props: any) => {
208
218
  const _logoMain = name ? <MainIcon title={name} /> : logoMain;
@@ -7,10 +7,19 @@ import MainIcon from './MainIcon';
7
7
  import PropTypes from 'prop-types';
8
8
  import React from 'react';
9
9
 
10
- const AuthWrapper = ({ version, name, copy, children, background = AuthBackground }) => {
10
+ export type AuthWrapperProps = {
11
+ version: string;
12
+ name: string;
13
+ copy?: string;
14
+ background?: React.ReactNode | React.ComponentType;
15
+ children: React.ReactNode;
16
+ logo?: React.ReactNode;
17
+ };
18
+
19
+ const AuthWrapper = ({ version, name, copy, children, logo, background = AuthBackground }: AuthWrapperProps) => {
11
20
  return (
12
21
  <Box sx={{ minHeight: '100vh' }}>
13
- {React.isValidElement(background) ? background : React.createElement(background)}
22
+ {React.isValidElement(background) ? background : React.createElement(background as any)}
14
23
  <Grid
15
24
  container
16
25
  direction="column"
@@ -19,8 +28,8 @@ const AuthWrapper = ({ version, name, copy, children, background = AuthBackgroun
19
28
  minHeight: '100vh'
20
29
  }}
21
30
  >
22
- <Grid item xs={12} sx={{ ml: 3, mt: 3 }}>
23
- <MainIcon title={name} />
31
+ <Grid item xs={12} sx={{ ml: 3 }}>
32
+ {logo ? logo : <MainIcon title={name} />}
24
33
  </Grid>
25
34
  <Grid item xs={12}>
26
35
  <Grid
@@ -37,8 +37,7 @@ const NavGroup = ({ item, lastItem, remItems, lastItemId, setSelectedItems, sele
37
37
  const { pathname } = { pathname: '' }; // useLocation()
38
38
  const { horizontal, downLg } = useLayoutMediaState();
39
39
  const menu = useMenuConfig();
40
- const { drawerOpen, selectedID } = menu;
41
- const { activeID } = useMenuConfig();
40
+ const { drawerOpen, selectedID, activeID } = menu;
42
41
 
43
42
  const [anchorEl, setAnchorEl] = useState(null);
44
43
  const [currentItem, setCurrentItem] = useState(item);
@@ -1,8 +1,8 @@
1
1
  import { Stack, Typography } from '@mui/material';
2
-
3
- import PropTypes from 'prop-types';
4
-
5
- const MainIcon = ({ title }) => (
2
+ export type MainIconProps = {
3
+ title: string;
4
+ };
5
+ const MainIcon = ({ title }: MainIconProps) => (
6
6
  <Stack direction="row">
7
7
  <Typography variant="h2" sx={{ fontWeight: 'regular', letterSpacing: -2.5 }}>
8
8
  a.
@@ -14,8 +14,4 @@ const MainIcon = ({ title }) => (
14
14
  </Stack>
15
15
  );
16
16
 
17
- MainIcon.propTypes = {
18
- title: PropTypes.string.isRequired
19
- };
20
-
21
17
  export default MainIcon;
@@ -9,7 +9,7 @@ import PropTypes from 'prop-types';
9
9
  import _ from 'lodash';
10
10
  import { useEffect } from 'react';
11
11
 
12
- const ActivatePage = ({ name, copy, version, background }: BaseAuthProps) => {
12
+ const ActivatePage = ({ name, copy, logo, version, background }: BaseAuthProps) => {
13
13
  const translate = useTranslate();
14
14
  const authProvider = useAuthProvider();
15
15
  const notify = useNotify();
@@ -31,7 +31,7 @@ const ActivatePage = ({ name, copy, version, background }: BaseAuthProps) => {
31
31
  });
32
32
  }, [token]);
33
33
  return (
34
- <AuthWrapper name={name} copy={copy} version={version} background={background}>
34
+ <AuthWrapper name={name} copy={copy} logo={logo} version={version} background={background}>
35
35
  <Grid container spacing={3}>
36
36
  <Grid item xs={12}>
37
37
  <Stack direction="row" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
@@ -11,11 +11,11 @@ import { useEffect } from 'react';
11
11
 
12
12
  export type LoginPageProps = BaseAuthProps & {
13
13
  /**
14
- * Indica se abilitare o meno la schermata di recupero password.
15
- * Se abilitato è opportuno registrare una rotta a /recover con un componente
16
- * che si occupi del recupero, puoi utilizzare direttamente il componente di Applica
14
+ * Indicates whether to enable the password recovery screen.
15
+ * If enabled, it is advisable to register a route to /recover with a component
16
+ * that takes care of recovery, you can use the Applica component directly for this
17
17
  *
18
- * @see RecoverPage per maggiori informazioni.
18
+ * @see RecoverPage for more information.
19
19
  * @example
20
20
  * import { RecoverPage } from "@applica-software-guru/react-admin";
21
21
  * <CustomRoutes noLayout>
@@ -24,11 +24,11 @@ export type LoginPageProps = BaseAuthProps & {
24
24
  */
25
25
  enablePasswordRecover?: boolean;
26
26
  /**
27
- * Indica se abilitare o meno la schermata di registrazione.
28
- * Se abilitato è opportuno registrare una rotta a /register con un componente
29
- * che si occupi della registrazione, puoi utilizzare direttamente il componente di Applica
27
+ * Indicates whether to enable the registration screen.
28
+ * If enabled, it is advisable to register a route to /register with a component
29
+ * that takes care of registration, you can use the Applica component directly for this
30
30
  *
31
- * @see RegisterPage per maggiori informazioni.
31
+ * @see RegisterPage for more information.
32
32
  * @example
33
33
  * import { RegisterPage } from "@applica-software-guru/react-admin";
34
34
  * <CustomRoutes noLayout>
@@ -37,12 +37,12 @@ export type LoginPageProps = BaseAuthProps & {
37
37
  */
38
38
  enableRegistration?: boolean;
39
39
  /**
40
- * Indica la pagina a cui reindirizzare l'utente dopo il login.
41
- * Se non specificata viene utilizzata la home page di react-admin.
40
+ * Indicates the page to redirect the user to after login.
41
+ * If not specified, the react-admin home page is used.
42
42
  */
43
43
  redirectTo: string;
44
44
  };
45
- const LoginPage = ({ version, name, copy, enablePasswordRecover, enableRegistration, redirectTo, background }: LoginPageProps) => {
45
+ const LoginPage = ({ version, name, copy, logo, enablePasswordRecover, enableRegistration, redirectTo, background }: LoginPageProps) => {
46
46
  const [loading, setLoading] = useSafeSetState(false);
47
47
  const login = useLogin();
48
48
  const translate = useTranslate();
@@ -78,7 +78,7 @@ const LoginPage = ({ version, name, copy, enablePasswordRecover, enableRegistrat
78
78
  });
79
79
  };
80
80
  return (
81
- <AuthWrapper name={name} version={version} copy={copy} background={background}>
81
+ <AuthWrapper name={name} version={version} copy={copy} logo={logo} background={background}>
82
82
  <Grid container spacing={3}>
83
83
  <Grid item xs={12}>
84
84
  <Stack direction="row" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
@@ -10,7 +10,7 @@ import { Link } from 'react-router-dom';
10
10
  import PropTypes from 'prop-types';
11
11
  import { TextInput } from '../ra-inputs';
12
12
 
13
- const RecoverPage = ({ name, copy, version, background }: BaseAuthProps) => {
13
+ const RecoverPage = ({ name, copy, logo, version, background }: BaseAuthProps) => {
14
14
  const [loading, setLoading] = useState(false);
15
15
  const translate = useTranslate();
16
16
  const redirect = useRedirect();
@@ -34,7 +34,7 @@ const RecoverPage = ({ name, copy, version, background }: BaseAuthProps) => {
34
34
  .finally(() => setLoading(false));
35
35
  };
36
36
  return (
37
- <AuthWrapper name={name} copy={copy} version={version} background={background}>
37
+ <AuthWrapper name={name} copy={copy} logo={logo} version={version} background={background}>
38
38
  <Grid container spacing={3}>
39
39
  <Grid item xs={12}>
40
40
  <Stack direction="row" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
@@ -10,7 +10,7 @@ import PropTypes from 'prop-types';
10
10
  import { TextInput } from '../ra-inputs';
11
11
  import { useState } from 'react';
12
12
 
13
- const RegisterPage = ({ name, copy, version }: BaseAuthProps) => {
13
+ const RegisterPage = ({ name, copy, version, logo, background }: BaseAuthProps) => {
14
14
  const [loading, setLoading] = useState(false);
15
15
  const translate = useTranslate();
16
16
  const redirect = useRedirect();
@@ -34,7 +34,7 @@ const RegisterPage = ({ name, copy, version }: BaseAuthProps) => {
34
34
  .finally(() => setLoading(false));
35
35
  };
36
36
  return (
37
- <AuthWrapper name={name} copy={copy} version={version}>
37
+ <AuthWrapper name={name} copy={copy} logo={logo} background={background} version={version}>
38
38
  <Grid container spacing={3}>
39
39
  <Grid item xs={12}>
40
40
  <Stack direction="row" justifyContent="space-between" alignItems="baseline" sx={{ mb: { xs: -0.5, sm: 0.5 } }}>
@@ -1,19 +1,22 @@
1
1
  export type BaseAuthProps = {
2
2
  /**
3
- * Versione dell'applicazione da mostrare.
3
+ * Application version to show.
4
4
  */
5
5
  version: string;
6
6
  /**
7
- * Nome dell'applicazione da mostrare.
7
+ * Application name to show.
8
8
  */
9
9
  name: string;
10
10
  /**
11
- * Copyright da mostrare nella pagina.
11
+ * Copy to show.
12
12
  */
13
13
  copy?: string;
14
14
  /**
15
- * Immagine di sfondo della pagina.
16
- * Se non specificata viene utilizzata l'immagine di default.
15
+ * Indicates top left logo to display in the login page.
16
+ */
17
+ logo?: React.ReactNode;
18
+ /**
19
+ * Background image to show.
17
20
  *
18
21
  * @see AuthBackground per maggiori informazioni.
19
22
  * @example
@@ -1,51 +1,48 @@
1
1
  import _ from 'lodash';
2
- import { useEffect, useState } from 'react';
2
+ import { useEffect, useRef, useState } from 'react';
3
3
  import * as yup from 'yup';
4
4
  import { LocalStorage } from '../utils/localStorage';
5
5
 
6
6
  const localStorageInstance = new LocalStorage();
7
7
 
8
- function useLocalStorage(key: string, defaultValue?: unknown): [unknown, (newValue: unknown) => unknown] {
9
- yup.string().required().validateSync(key);
10
-
11
- function buildSetter(key: string, currentValue: unknown, callback: (newValue: unknown) => unknown): (newValue: unknown) => unknown {
12
- return function (newValue: unknown) {
13
- const updatedValue = _.isFunction(newValue) ? newValue(currentValue) : newValue;
14
- localStorageInstance.set(key, updatedValue);
15
- callback(updatedValue);
16
- return updatedValue;
17
- };
18
- }
8
+ type ISetter = (newValue: unknown) => unknown;
19
9
 
20
- const [fallbackValue, updateFallbackValue] = useState(defaultValue),
21
- [state, updateState] = useState(localStorageInstance.get(key) ?? defaultValue),
22
- [setter, updateSetter] = useState(() => buildSetter(key, state, updateState));
10
+ function buildSetter(key: string, currentValue: unknown, callback: ISetter): ISetter {
11
+ return function (newValue: unknown) {
12
+ const updatedValue = _.isFunction(newValue) ? newValue(currentValue) : newValue;
13
+ localStorageInstance.set(key, updatedValue);
14
+ callback(updatedValue);
15
+ return updatedValue;
16
+ };
17
+ }
23
18
 
24
- useEffect(() => {
25
- if (!_.isEqual(defaultValue, fallbackValue)) {
26
- updateFallbackValue(defaultValue);
27
- }
28
- }, [defaultValue, fallbackValue, updateFallbackValue]);
19
+ function useLocalStorage(key: string, defaultValue?: unknown): [unknown, (newValue: unknown) => unknown] {
20
+ yup.string().required().validateSync(key);
21
+ const [state, setState] = useState(localStorageInstance.get(key) ?? defaultValue),
22
+ defaultValueRef = useRef<unknown | undefined>(defaultValue),
23
+ storedDefaultValue = _.isEqual(defaultValueRef.current, defaultValue) ? defaultValueRef.current : defaultValue,
24
+ setterRef = useRef<{ key: string; value: unknown; setter: ISetter } | undefined>(),
25
+ storedSetter = setterRef.current;
29
26
 
30
27
  useEffect(() => {
31
- updateState(localStorageInstance.get(key) ?? fallbackValue);
32
- }, [key, fallbackValue, updateState]);
28
+ setState(localStorageInstance.get(key) ?? storedDefaultValue);
29
+ }, [key, storedDefaultValue, setState]);
33
30
 
34
31
  useEffect(() => {
35
32
  function listener(value: unknown) {
36
- updateState(value);
33
+ setState(value);
37
34
  }
38
35
  localStorageInstance.watch(key, listener);
39
36
  return () => {
40
37
  localStorageInstance.unwatch(key, listener);
41
38
  };
42
- }, [key, updateState]);
39
+ }, [key, setState]);
43
40
 
44
- useEffect(() => {
45
- updateSetter(() => buildSetter(key, state, updateState));
46
- }, [key, state, updateState, updateSetter]);
41
+ if (key !== storedSetter?.key || !_.isEqual(state, storedSetter?.value)) {
42
+ setterRef.current = { key, value: state, setter: buildSetter(key, state, setState) };
43
+ }
47
44
 
48
- return [state, setter];
45
+ return [state, setterRef.current?.setter ?? _.noop];
49
46
  }
50
47
 
51
48
  export default useLocalStorage;