React项目集成PayPal按钮出现paypal未定义等错误如何解决
问题原因
- 第一个错误
'paypal' is not defined no-undef有两个触发点:- 你给CDN脚本加了
defer属性,脚本会在页面解析完成后才异步加载,React组件初始化执行的时候,paypal全局变量还没有挂载到window对象上 - ESLint默认不识别未声明的全局变量,即使后续paypal加载完成,ESLint也会提前抛出规则错误
- 你给CDN脚本加了
- 第二个错误
TypeError: paypal_checkout__WEBPACK_IMPORTED_MODULE_4___default.a.Buttons is undefined的原因:- 你安装的
paypal-checkout是PayPal旧版的前端SDK,和你在index.html引入的新版JS SDK API不兼容,旧版本没有Buttons相关的导出,所以调用会报错。
- 你安装的
解决方案
- 先卸载旧版本的无用依赖
npm uninstall paypal-checkout # 如果你用yarn则执行 yarn remove paypal-checkout
- 处理ESLint的全局变量检测报错
在你当前的PayPal组件文件顶部添加一行注释,告诉ESLintpaypal是全局变量,跳过未定义检测:
/* global paypal */ import React, {useState, useEffect} from 'react'; // 剩下的import保持不变
如果要全局生效,可以在项目的.eslintrc配置文件中添加配置:
{ "globals": { "paypal": "readonly" } }
- 调整组件逻辑,等待PayPal SDK加载完成后再初始化按钮
不要在组件外层直接初始化PayPalButton,放到组件内部等SDK加载完成后再执行,避免异步加载导致的变量不存在问题,修改后的完整组件代码示例:
/* global paypal */ import React, {useState, useEffect} from 'react'; import {useDispatch} from 'react-redux'; import {useHistory} from 'react-router-dom'; import ReactDOM from 'react-dom'; import * as actionsReservations from '../../reservation/actions'; import {Errors} from '..'; const PayPalReserve = ({deposit, menu, companyId, reservationDate, periodType, diners}) => { const dispatch = useDispatch(); const history = useHistory(); const [backendErrors, setBackendErrors] = useState(null); // 添加状态控制按钮是否加载完成 const [PayPalButton, setPayPalButton] = useState(null); // 组件挂载后检测SDK加载状态,初始化按钮 useEffect(() => { // 如果paypal已经加载完成直接初始化 if (window.paypal) { initPayPalButton(); return; } // 如果还没加载,监听脚本的load事件 const paypalScript = document.querySelector('script[src*="paypal.com/sdk/js"]'); if (paypalScript) { paypalScript.addEventListener('load', initPayPalButton); } return () => { if (paypalScript) { paypalScript.removeEventListener('load', initPayPalButton); } } }, []); const initPayPalButton = () => { const Button = window.paypal.Buttons.driver("react", { React, ReactDOM }); setPayPalButton(Button); }; const createOrder = (data,actions) => { return actions.order.create({ purchase_units:[ { amount:{ value: deposit }, }, ], }); }; const onApprove = (data, actions) => { return actions.order.capture().then(response => { dispatch(actionsReservations.reservation( menu.id, companyId, reservationDate, periodType, diners, response.id, () => history.push('/reservation/reservation-completed'), errors => setBackendErrors(errors) )); console.log(response); }); } // 按钮加载完成前可以渲染占位符 if (!PayPalButton) return <div>加载支付按钮中...</div>; return ( <PayPalButton createOrder={createOrder} onApprove={onApprove} /> ); }; export default PayPalReserve;
内容的提问来源于stack exchange,提问作者Ulyses Evans
相关产品推荐
相关产品推荐

