Skip to content

Commit

Permalink
Performance degradation
Browse files Browse the repository at this point in the history
  • Loading branch information
Randagio13 committed Aug 1, 2024
1 parent 0b33248 commit 8302bec
Show file tree
Hide file tree
Showing 8 changed files with 1,344 additions and 1,205 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
},
"devDependencies": {
"@commercelayer/eslint-config-ts-react": "^1.4.5",
"husky": "^9.0.11",
"husky": "^9.1.4",
"lerna": "^8.1.4",
"typescript": "^5.5.2"
"typescript": "^5.5.4"
},
"pnpm": {
"overrides": {
Expand Down
8 changes: 6 additions & 2 deletions packages/rapid-form/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@
"vitest": "^1.6.0"
},
"peerDependencies": {
"react": "^16.8.0 || ^17 || ^18 || ^19"
"react": "^16.9.0",
"react-dom": "^16.9.0"
},
"dependencies": {
"@example/basics": "link:/Users/alessandrocasazza/Documents/GitHub/okeo-academy"
}
}
}
21 changes: 21 additions & 0 deletions packages/rapid-form/src/events.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
type EventHandler = (event: Event) => void;
type EventListenersMap = { [event: string]: EventHandler };

const eventListeners = new WeakMap<Element, EventListenersMap>();

export function addTrackedEventListener(
element: Element,
event: string,
handler: EventHandler
): void {
if (!eventListeners.has(element)) {
eventListeners.set(element, {});
}
const listeners = eventListeners.get(element)!;
listeners[event] = handler;
element.addEventListener(event, handler);
}

export function hasEventListener(element: Element, event: string): boolean {
return eventListeners.has(element) && !!eventListeners.get(element)?.[event];
}
2 changes: 1 addition & 1 deletion packages/rapid-form/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export function useRapidForm(): {
const [state, dispatch] = useReducer(reducer, initialState)
return {
refValidation: (ref, config) => {
validation({ ref, dispatch, config, state })
validation({ ref, dispatch, config })
},
...state
}
Expand Down
34 changes: 30 additions & 4 deletions packages/rapid-form/src/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,19 +45,45 @@ export const initialState: State = {
errors: {}
}

type AnyObject = { [key: string]: any };

function isObject(item: any): item is AnyObject {
return item && typeof item === 'object' && !Array.isArray(item);
}

function deepMerge<T extends AnyObject, U extends AnyObject>(target: T, source: U): T & U {
const output = { ...target } as T & U;

for (const key in source) {
if (source.hasOwnProperty(key)) {
const targetValue = output[key];
const sourceValue = source[key];

if (isObject(sourceValue) && isObject(targetValue)) {
// Recursively merge nested objects
output[key] = deepMerge(targetValue, sourceValue);
} else {
// Overwrite the target with the source value
output[key as keyof U] = sourceValue as (T & U)[Extract<keyof U, string>];
}
}
}

return output;
}
/**
* The reducer function that handles state updates based on dispatched actions.
* @param state The current state.
* @param action The action to be dispatched.
* @returns The new state after applying the action.
*/
export const reducer: Reducer<State, Action> = (state, action) => {
switch (action.type) {
export const reducer: Reducer<State, Action> = (state, { type, ...data}) => {
switch (type) {
case 'setValue':
case 'setError':
return { values: { ...state.values, ...action.values}, errors: { ...state.errors, ...action.errors } }
return deepMerge(state, data)
case 'reset':
return { values: action.values, errors: {} }
return { values: data.values, errors: {} }
}
}

Expand Down
16 changes: 7 additions & 9 deletions packages/rapid-form/src/validation.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { type Dispatch } from 'react'
import { type State, type Action } from './reducer.js'
import { addTrackedEventListener, hasEventListener } from './events.js'

type EventType = 'change' | 'blur' | 'input'

Expand Down Expand Up @@ -41,10 +42,6 @@ export interface ValidationProps {
resetOnSubmit?: boolean
}
| undefined
/**
* State of the reducer
*/
state?: State
}

/**
Expand Down Expand Up @@ -104,7 +101,6 @@ export function validation({
ref,
dispatch,
config,
state
}: ValidationProps): void {
const elements = ref?.elements
let eventType = config?.eventType ?? 'input'
Expand Down Expand Up @@ -133,17 +129,18 @@ export function validation({
const element = elements[i]
if (element != null) {
const name = element.getAttribute('name')
const hasEvent = name != null ? state?.values?.[name] != null : true
if (hasEvent) {
const hasEvent = hasEventListener(element, eventType)
if (hasEvent || !name) {
continue
}
debugger
const isRequired = element?.hasAttribute('required')
if (isRequired) {
const currentElementName = element.getAttribute('name')
eventType =
config?.validations?.[`${currentElementName}`]?.eventType ??
eventType
element?.addEventListener(eventType, function (e) {
addTrackedEventListener(element, eventType, function (e) {
const target = e.target as HTMLInputElement
const val = target.value.trim()
const isValid =
Expand Down Expand Up @@ -181,7 +178,8 @@ export function validation({
[target.name]: {
name: target.name,
value: val,
isInvalid: false
isInvalid: false,
message: ''
}
}
})
Expand Down
2 changes: 1 addition & 1 deletion packages/rapid-form/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

/* Language and Environment */
"target": "ESNext" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
"lib": ["dom", "ES7", "ESNext"], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
"jsx": "react-jsx", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
Expand Down
Loading

0 comments on commit 8302bec

Please sign in to comment.