react-plaid-link
Version:
A React component for Plaid Link
107 lines (92 loc) • 2.89 kB
text/typescript
import { useEffect, useState } from 'react';
import useScript from './react-script-hook';
import { createPlaid, PlaidFactory } from './factory';
import {
PlaidLinkOptions,
PlaidLinkOptionsWithLinkToken,
PlaidLinkOptionsWithPublicKey,
} from './types';
import { PLAID_LINK_STABLE_URL } from './constants';
const noop = () => {};
/**
* This hook loads Plaid script and manages the Plaid Link creation for you.
* You get easy open & exit methods to call and loading & error states.
*
* This will destroy the Plaid UI on un-mounting so it's up to you to be
* graceful to the user.
*
* A new Plaid instance is created every time the token and products options change.
* It's up to you to prevent unnecessary re-creations on re-render.
*/
export const usePlaidLink = (options: PlaidLinkOptions) => {
// Asynchronously load the plaid/link/stable url into the DOM
const [loading, error] = useScript({
src: PLAID_LINK_STABLE_URL,
checkForExisting: true,
});
// internal state
const [plaid, setPlaid] = useState<PlaidFactory | null>(null);
const [iframeLoaded, setIframeLoaded] = useState(false);
const products = ((options as PlaidLinkOptionsWithPublicKey).product || [])
.slice()
.sort()
.join(',');
useEffect(() => {
// If the link.js script is still loading, return prematurely
if (loading) {
return;
}
// If the token, publicKey, and received redirect URI are undefined, return prematurely
if (
!options.token &&
!(options as PlaidLinkOptionsWithPublicKey).publicKey &&
!(options as PlaidLinkOptionsWithLinkToken).receivedRedirectUri
) {
return;
}
if (error || !window.Plaid) {
// eslint-disable-next-line no-console
console.error('Error loading Plaid', error);
return;
}
// if an old plaid instance exists, destroy it before
// creating a new one
if (plaid != null) {
plaid.exit({ force: true }, () => plaid.destroy());
}
const next = createPlaid(
{
...options,
onLoad: () => {
setIframeLoaded(true);
options.onLoad && options.onLoad();
},
},
window.Plaid.create
);
setPlaid(next);
// destroy the Plaid iframe factory
return () => next.exit({ force: true }, () => next.destroy());
}, [
loading,
error,
(options as PlaidLinkOptionsWithPublicKey).publicKey,
options.token,
products,
]);
const ready = plaid != null && (!loading || iframeLoaded);
const openNoOp = () => {
if (!options.token) {
console.warn(
'react-plaid-link: You cannot call open() without a valid token supplied to usePlaidLink. This is a no-op.'
);
}
};
return {
error,
ready,
submit: plaid ? plaid.submit : noop,
exit: plaid ? plaid.exit : noop,
open: plaid ? plaid.open : openNoOp,
};
};