Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Proposal] Promise-based HOC wrapper for MailchimpSubscribe #70

Open
smac89 opened this issue Sep 2, 2021 · 2 comments
Open

[Proposal] Promise-based HOC wrapper for MailchimpSubscribe #70

smac89 opened this issue Sep 2, 2021 · 2 comments

Comments

@smac89
Copy link

smac89 commented Sep 2, 2021

I was recently tasked with implementing mailchimp subscription in react, but I found the implementation of MailchimpSubscrbe to be rather inconvenient for properly managing state.

The problem

In our case, we use react-google-recaptcha and react-final-form, but the problem is that final form expects that once we return from the onSubmit function, that the form has been submitted. Inside the onSubmit function, we wait for the recaptcha to complete, but when it comes to the subscribe callback exposed by MailchimpSubscribe, it does not return a promise; So calling that function inside the onSubmit function will immediately return which leads the form to assume the subscription was successful.

Solution

I came up with a higher-order component which simply exposes a function that returns a promise and you don't have to worry about status; Just wait for the function to complete and if there is an error at the end, you can "catch" that and do something with it. Here it is (hope you don't mind typescript 😄 ):

/* eslint-disable react-hooks/rules-of-hooks */
import React, { useCallback, useEffect, useRef } from "react";
import MailchimpSubscribe, { DefaultFormFields } from "react-mailchimp-subscribe";

interface MailchimpSubscribeHOCProps<MCF> {
    mailchimpSubscribe: (formFields: MCF) => Promise<void>;
}

/**
 * Wraps a component with the MailchimpSubscribe component and exposes a simple subscribe
 * function which returns a promise
 *
 * @param Wrapped The component to wrap
 * @param mailchimpSubscribeUrl The POST url used for subscribing via mailchimp
 * @returns A component which has the ability to subscribe to
 */
export default function withMailchimpSubscribe<T = {}, MCF = DefaultFormFields>(Wrapped: React.ComponentType<T & MailchimpHOCProps<MCF>>, mailchimpSubscribeUrl: string): React.FC<T> {
    const subscribeSuccess = useRef<() => void>(null);
    const subscribeError = useRef<(error?: any) => void>(null);

    useEffect(() => () => {
        // Avoid memory leaks(?) by removing any held references
        subscribeSuccess.current = null;
        subscribeError.current = null;
    }, []);

    // eslint-disable-next-line react-hooks/rules-of-hooks
    return useCallback((props: T) => (<MailchimpSubscribe<MCF>
        url={mailchimpSubscribeUrl}
        render={({ subscribe, status, message }) => {
            const mailchimpSubmit: (formFields: MCF) => Promise<void> = (formFields: MCF) => {
                subscribe(formFields);
                return new Promise<void>((resolve, reject) => {
                    subscribeSuccess.current = resolve;
                    subscribeError.current = reject;
                });
            };

            if (status === 'success' && subscribeSuccess.current != null) {
                subscribeSuccess.current();
            } else if (status === 'error' && subscribeError.current != null) {
                subscribeError.current(message);
            }
            return <Wrapped mailchimpSubscribe={mailchimpSubmit} {...props} />;
        }} />
        // eslint-disable-next-line react-hooks/exhaustive-deps
    ), [mailchimpSubscribeUrl]);
}

The promise resolves to nothing if the subscription was successful, otherwise it fails with an error message if the status is error.

Example

const mailchimpUrl = "...";
const MyCustomForm: React.FC = withMailchimpSubscribe(({ mailchimpSubscribe: subscribe }) => {
    // do some state management here

   return (
       <Form .../>
   );
}, mailchimpUrl);
@revolunet
Copy link
Owner

revolunet commented Sep 2, 2021

The current implementation is quite outdated indeed

What about a hook version like const { status, subscribe } = useMailchimpSubscribe(url); ?

@smac89
Copy link
Author

smac89 commented Sep 7, 2021

Oh yes a hook will be a much better design.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants