Seeking Solution for Button Component's onClick Event Issue

Hello,

we have implemented a wrapper for our button component. This is registered via the widgetMap, as illustrated in the code snippet below:

 <CRUDViews.FormEngineView
  {...props}
  attachmentHandler={attachmentHandler}
  widgetMap={{
    ...DefaultWidgetMap,
    Button: createButtonComponent(props)
  }}
/>

export function createButtonComponent(
    viewProps: React.PropsWithChildren<View>
): (props: ButtonProps) => JSX.Element { 
    return function ButtonComponent(props: ButtonProps): JSX.Element {
        const modifiedProps = modifyProps(props);

        return (
            <Button {...modifiedProps}></Button>
        );
    }
}

While it works as expected, we have encountered a minor hiccup. The problem is that the button fails to fire the onClick event if an input field is modified and the button is clicked immediately without loosing the focus.

Our theory is that the blur event may be refreshing the buttons, causing the user to click on an older version of the button, which is then promptly removed. As a workaround, we have been using the onMouseDown event to manually call the onClick function. While this works, it is not the best solution.

If you have any suggestions on how we can better address this issue, we would be very grateful to hear from you.

Best regards.

Hi @dmytro-clear-peat , can you try to declare in the WidgetMap “Button: ButtonComponent” instead of calling the function?

Hello @binh-deep-cache, thank you for a quick reply.
Yes, it works this way. The issue lies in the requirement to modify the component’s props based on viewProps. If a particular model condition is met, the button should be deactivated.
Sorry, I oversimplified my code-example. The actual scenario is as follows:

export function createButtonComponent(
    viewProps: React.PropsWithChildren<View>
): (props: ButtonProps) => JSX.Element {
    const acitve = isActive(viewProps);

    return function ButtonComponent(props: ButtonProps): JSX.Element {
        const propsModified: ButtonProps = { ...props };
        if (props.label === ACTIVE_LABEL && active === true) {
            propsModified.disabled = true;
        }

        return (
            <Button
                {...propsModified}
            ></Button>
        );
    };
}

Hi @dmytro-clear-peat

The way you create your button is not a good practice, since the reference of your ButtonComponent is constantly re-created whenever the CRUDViews.FormEngineView is re-rendered. This leads to React not be able to aware of whether the Button Component is updated, so that React will always unmount it then re-mount a new button every time a re-render happens. That is why the onClick handler is sometimes not register when you blur any input component on the form. We wanted it to be re-rendered/updated, not unmounted.

You should try to go with @binh-deep-cache’s recommendation to prevent your ButtonComponent from being re-created. To archieve in your scenario, here are a few options:

  1. Use useMemo and reduce the amount of dependencies needed.
  2. The information about the activity can be retrieved multiple ways via Client selector like latestActivity(). Therefore, you can get this information with-in the Button component instead of derive it from the FormEngine’s ViewContainer. As the result, the ButtonComponent will not be re-created on re-render.
  3. Combine those with React’s context to only pass in needed information like the activityId.

Hi @tri-sheer-boulder,

Works like a charm! Thank you so much.

Best regards.