Skip to content

Commit 3cd647c

Browse files
committed
fix(index): group state & effects, memoize functions
1 parent ff3ea17 commit 3cd647c

File tree

3 files changed

+507
-45
lines changed

3 files changed

+507
-45
lines changed

src/index.tsx

+96-45
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import React, {
88
Dispatch,
99
SetStateAction,
1010
ReactNode,
11+
useCallback,
1112
} from 'react';
1213

1314
import GoTrue, {
@@ -36,6 +37,12 @@ const defaultSettings = {
3637
},
3738
};
3839

40+
const errors = {
41+
noUserFound: 'No current user found - are you logged in?',
42+
};
43+
44+
type MaybeUserPromise = Promise<User | undefined>;
45+
3946
export type ReactNetlifyIdentityAPI = {
4047
user: User | undefined;
4148
/** not meant for normal use! you should mostly use one of the other exported methods to update the user instance */
@@ -46,19 +53,19 @@ export type ReactNetlifyIdentityAPI = {
4653
email: string,
4754
password: string,
4855
data: Object
49-
) => Promise<User | undefined>;
56+
) => MaybeUserPromise;
5057
loginUser: (
5158
email: string,
5259
password: string,
5360
remember?: boolean
54-
) => Promise<User | undefined>;
55-
logoutUser: () => Promise<User | undefined>;
61+
) => MaybeUserPromise;
62+
logoutUser: () => MaybeUserPromise;
5663
requestPasswordRecovery: (email: string) => Promise<void>;
5764
recoverAccount: (
5865
token: string,
5966
remember?: boolean | undefined
6067
) => Promise<User>;
61-
updateUser: (fields: { data: object }) => Promise<User | undefined>;
68+
updateUser: (fields: { data: object }) => MaybeUserPromise;
6269
getFreshJWT: () => Promise<string>;
6370
authedFetch: {
6471
get: (endpoint: string, obj?: {}) => Promise<any>;
@@ -119,14 +126,20 @@ export function useNetlifyIdentity(
119126
[url]
120127
);
121128

129+
/******* STATE and EFFECTS */
130+
122131
const [user, setUser] = useState<User | undefined>(
123132
goTrueInstance.currentUser() || undefined
124133
);
125-
const _setUser = (_user: User | undefined) => {
126-
setUser(_user);
127-
onAuthChange(_user); // if someone's subscribed to auth changes, let 'em know
128-
return _user; // so that we can continue chaining
129-
};
134+
135+
const _setUser = useCallback(
136+
(_user: User | undefined) => {
137+
setUser(_user);
138+
onAuthChange(_user); // if someone's subscribed to auth changes, let 'em know
139+
return _user; // so that we can continue chaining
140+
},
141+
[onAuthChange]
142+
);
130143

131144
const [param, setParam] = useState<TokenParam>(defaultParam);
132145

@@ -140,71 +153,109 @@ export function useNetlifyIdentity(
140153
}
141154
}, []);
142155

156+
const [settings, setSettings] = useState<Settings>(defaultSettings);
157+
158+
useEffect(() => {
159+
goTrueInstance.settings
160+
.bind(goTrueInstance)()
161+
.then(x => setSettings(x));
162+
}, []);
163+
143164
/******* OPERATIONS */
144165
// make sure the Registration preferences under Identity settings in your Netlify dashboard are set to Open.
145166
// https://react-netlify-identity.netlify.com/login#access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NTY0ODY3MjEsInN1YiI6ImNiZjY5MTZlLTNlZGYtNGFkNS1iOTYzLTQ4ZTY2NDcyMDkxNyIsImVtYWlsIjoic2hhd250aGUxQGdtYWlsLmNvbSIsImFwcF9tZXRhZGF0YSI6eyJwcm92aWRlciI6ImdpdGh1YiJ9LCJ1c2VyX21ldGFkYXRhIjp7ImF2YXRhcl91cmwiOiJodHRwczovL2F2YXRhcnMxLmdpdGh1YnVzZXJjb250ZW50LmNvbS91LzY3NjQ5NTc_dj00IiwiZnVsbF9uYW1lIjoic3d5eCJ9fQ.E8RrnuCcqq-mLi1_Q5WHJ-9THIdQ3ha1mePBKGhudM0&expires_in=3600&refresh_token=OyA_EdRc7WOIVhY7RiRw5w&token_type=bearer
146167
/******* external oauth */
147168

148-
const loginProvider = (provider: Provider) => {
149-
const url = goTrueInstance.loginExternalUrl(provider);
150-
window.location.href = url;
151-
};
152-
const acceptInviteExternalUrl = (provider: Provider, token: string) =>
153-
goTrueInstance.acceptInviteExternalUrl(provider, token);
154-
const _settings = goTrueInstance.settings.bind(goTrueInstance);
155-
const [settings, setSettings] = useState<Settings>(defaultSettings);
156-
useEffect(() => {
157-
_settings().then(x => setSettings(x));
158-
}, []);
169+
const loginProvider = useCallback(
170+
(provider: Provider) => {
171+
const url = goTrueInstance.loginExternalUrl(provider);
172+
window.location.href = url;
173+
},
174+
[goTrueInstance]
175+
);
176+
177+
const acceptInviteExternalUrl = useCallback(
178+
(provider: Provider, token: string) =>
179+
goTrueInstance.acceptInviteExternalUrl(provider, token),
180+
[goTrueInstance]
181+
);
159182

160183
/******* email auth */
161-
const signupUser = (email: string, password: string, data: Object) =>
162-
goTrueInstance.signup(email, password, data).then(_setUser); // TODO: make setUser optional?
163-
const loginUser = (
164-
email: string,
165-
password: string,
166-
remember: boolean = true
167-
) => goTrueInstance.login(email, password, remember).then(_setUser);
168-
const requestPasswordRecovery = (email: string) =>
169-
goTrueInstance.requestPasswordRecovery(email);
170-
const recoverAccount = (token: string, remember?: boolean | undefined) =>
171-
goTrueInstance.recover(token, remember);
172-
const updateUser = (fields: { data: object }) => {
173-
if (user == null) {
174-
throw new Error('No current user found - are you logged in?');
175-
} else {
184+
const signupUser = useCallback(
185+
(email: string, password: string, data: Object) =>
186+
// TODO: make setUser optional?
187+
goTrueInstance.signup(email, password, data).then(_setUser),
188+
[goTrueInstance]
189+
);
190+
191+
const loginUser = useCallback(
192+
(email: string, password: string, remember: boolean = true) =>
193+
goTrueInstance.login(email, password, remember).then(_setUser),
194+
[goTrueInstance, _setUser]
195+
);
196+
197+
const requestPasswordRecovery = useCallback(
198+
(email: string) => goTrueInstance.requestPasswordRecovery(email),
199+
[goTrueInstance]
200+
);
201+
202+
const recoverAccount = useCallback(
203+
(token: string, remember?: boolean | undefined) =>
204+
goTrueInstance.recover(token, remember),
205+
[goTrueInstance]
206+
);
207+
208+
const updateUser = useCallback(
209+
(fields: { data: object }) => {
210+
if (!user) {
211+
throw new Error(errors.noUserFound);
212+
}
213+
176214
return user!
177215
.update(fields) // e.g. { data: { email: "example@example.com", password: "password" } }
178216
.then(_setUser);
217+
},
218+
[user]
219+
);
220+
221+
const getFreshJWT = useCallback(() => {
222+
if (!user) {
223+
throw new Error(errors.noUserFound);
179224
}
180-
};
181-
const getFreshJWT = () => {
182-
if (!user) throw new Error('No current user found - are you logged in?');
225+
183226
return user.jwt();
184-
};
185-
const logoutUser = () => {
186-
if (!user) throw new Error('No current user found - are you logged in?');
227+
}, [user]);
228+
229+
const logoutUser = useCallback(() => {
230+
if (!user) {
231+
throw new Error(errors.noUserFound);
232+
}
233+
187234
return user.logout().then(() => _setUser(undefined));
188-
};
235+
}, [user]);
189236

190237
const genericAuthedFetch = (method: string) => (
191238
endpoint: string,
192-
obj = {}
239+
options: RequestInit = {}
193240
) => {
194-
if (!user || !user.token || !user.token.access_token)
241+
if (!user?.token?.access_token) {
195242
throw new Error('no user token found');
243+
}
244+
196245
const defaultObj = {
197246
headers: {
198247
Accept: 'application/json',
199248
'Content-Type': 'application/json',
200249
Authorization: 'Bearer ' + user.token.access_token,
201250
},
202251
};
203-
const finalObj = Object.assign(defaultObj, { method }, obj);
252+
const finalObj = Object.assign(defaultObj, { method }, options);
253+
204254
return fetch(endpoint, finalObj).then(res =>
205255
finalObj.headers['Content-Type'] === 'application/json' ? res.json() : res
206256
);
207257
};
258+
208259
const authedFetch = {
209260
get: genericAuthedFetch('GET'),
210261
post: genericAuthedFetch('POST'),

0 commit comments

Comments
 (0)