Skip to content

Commit

Permalink
perf: use useSelector with granular approach in registration componen…
Browse files Browse the repository at this point in the history
…t to minimize rendrening
  • Loading branch information
mubbsharanwar committed Apr 1, 2024
1 parent 2d37b8b commit cd84744
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 66 deletions.
6 changes: 2 additions & 4 deletions src/register/RegistrationFields/EmailField/EmailField.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,8 @@ const EmailField = (props) => {
confirmEmailValue,
} = props;

const {
registrationFormData: backedUpFormData,
validationApiRateLimited,
} = useSelector(state => state.register);
const backedUpFormData = useSelector(state => state.register.registrationFormData);
const validationApiRateLimited = useSelector(state => state.register.validationApiRateLimited);

const [emailSuggestion, setEmailSuggestion] = useState({ ...backedUpFormData?.emailSuggestion });

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ const UsernameField = (props) => {
let className = '';
let suggestedUsernameDiv = null;
let iconButton = null;
const { usernameSuggestions, validationApiRateLimited } = useSelector(state => state.register);
const usernameSuggestions = useSelector(state => state.register.usernameSuggestions);
const validationApiRateLimited = useSelector(state => state.register.validationApiRateLimited);

/**
* We need to remove the placeholder from the field, adding a space will do that.
Expand Down
59 changes: 25 additions & 34 deletions src/register/RegistrationPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ import {
FORM_SUBMISSION_ERROR,
TPA_AUTHENTICATION_FAILURE,
} from './data/constants';
import getBackendValidations from './data/selectors';
import {
getBackendValidations, isFormValid, prepareRegistrationPayload,
isFormValid, prepareRegistrationPayload,
} from './data/utils';
import messages from './messages';
import { EmailField, NameField, UsernameField } from './RegistrationFields';
Expand Down Expand Up @@ -65,38 +66,26 @@ const RegistrationPage = (props) => {
institutionLogin,
} = props;

const {
registrationFormData: backedUpFormData,
registrationError,
registrationError: {
errorCode: registrationErrorCode,
} = {},
registrationResult,
shouldBackupState,
userPipelineDataLoaded,
submitState,
validations,
} = useSelector(state => state.register);

const {
fieldDescriptions,
optionalFields,
thirdPartyAuthApiStatus,
thirdPartyAuthContext,
thirdPartyAuthContext: {
autoSubmitRegForm,
errorMessage: thirdPartyAuthErrorMessage,
finishAuthUrl,
currentProvider,
providers,
secondaryProviders,
pipelineUserDetails,
},
} = useSelector(state => state.commonComponents);

const backendValidations = useMemo(
() => getBackendValidations(registrationError, validations), [registrationError, validations],
);
const backedUpFormData = useSelector(state => state.register.registrationFormData);
const registrationError = useSelector(state => state.register.registrationError);
const registrationErrorCode = registrationError?.errorCode;
const registrationResult = useSelector(state => state.register.registrationResult);
const shouldBackupState = useSelector(state => state.register.shouldBackupState);
const userPipelineDataLoaded = useSelector(state => state.register.userPipelineDataLoaded);
const submitState = useSelector(state => state.register.submitState);

const fieldDescriptions = useSelector(state => state.commonComponents.fieldDescriptions);
const optionalFields = useSelector(state => state.commonComponents.optionalFields);
const thirdPartyAuthApiStatus = useSelector(state => state.commonComponents.thirdPartyAuthApiStatus);
const autoSubmitRegForm = useSelector(state => state.commonComponents.thirdPartyAuthContext.autoSubmitRegForm);
const thirdPartyAuthErrorMessage = useSelector(state => state.commonComponents.thirdPartyAuthContext.errorMessage);
const finishAuthUrl = useSelector(state => state.commonComponents.thirdPartyAuthContext.finishAuthUrl);
const currentProvider = useSelector(state => state.commonComponents.thirdPartyAuthContext.currentProvider);
const providers = useSelector(state => state.commonComponents.thirdPartyAuthContext.providers);
const secondaryProviders = useSelector(state => state.commonComponents.thirdPartyAuthContext.secondaryProviders);
const pipelineUserDetails = useSelector(state => state.commonComponents.thirdPartyAuthContext.pipelineUserDetails);

const backendValidations = useSelector(getBackendValidations);
const queryParams = useMemo(() => getAllPossibleQueryParams(), []);
const tpaHint = useMemo(() => getTpaHint(), []);

Expand Down Expand Up @@ -130,7 +119,9 @@ const RegistrationPage = (props) => {
}
}
}, [ // eslint-disable-line react-hooks/exhaustive-deps
thirdPartyAuthContext,
thirdPartyAuthApiStatus,
thirdPartyAuthErrorMessage,
pipelineUserDetails,
userPipelineDataLoaded,
]);

Expand Down
33 changes: 33 additions & 0 deletions src/register/data/selectors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { createSelector } from 'reselect';

/**
* Selector for backend validations which processes the api output and generates a
* key value dict for field errors.
* @returns {{username: string}|{name: string}|*|{}|null}
*/
const getRegistrationError = state => state.register.registrationError;
const getValidations = state => state.register.validations;

const getBackendValidations = createSelector(
[getRegistrationError, getValidations],
(registrationError, validations) => {
if (validations) {
return validations.validationDecisions;
}

if (Object.keys(registrationError).length > 0) {
const fields = Object.keys(registrationError).filter(
(fieldName) => !(fieldName in ['errorCode', 'usernameSuggestions']),
);

const validationDecisions = {};
fields.forEach(field => {
validationDecisions[field] = registrationError[field][0].userMessage || '';
});
return validationDecisions;
}

return null;
});

export default getBackendValidations;
27 changes: 0 additions & 27 deletions src/register/data/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,30 +132,3 @@ export const prepareRegistrationPayload = (
payload = { ...payload, ...queryParams };
return payload;
};

/**
* A helper for backend validations selector. It processes the api output and generates a
* key value dict for field errors.
* @param registrationError
* @param validations
* @returns {{username: string}|{name: string}|*|{}|null}
*/
export const getBackendValidations = (registrationError, validations) => {
if (validations) {
return validations.validationDecisions;
}

if (Object.keys(registrationError).length > 0) {
const fields = Object.keys(registrationError).filter(
(fieldName) => !(fieldName in ['errorCode', 'usernameSuggestions']),
);

const validationDecisions = {};
fields.forEach(field => {
validationDecisions[field] = registrationError[field][0].userMessage || '';
});
return validationDecisions;
}

return null;
};

0 comments on commit cd84744

Please sign in to comment.