所以场景是我有一个React + Redux电子商务商店,并且有一个Checkout页面,其中列出了购物车中的所有物品。效果很好,每次添加产品时按钮都会重新渲染,但是,可以在结帐页面上从购物车中删除商品,并且尽管实际状态有所变化,但Paypal按钮仍使用旧状态(我假设是因为按钮没有被重新渲染)。我将按钮包装在useEffect函数中,该函数应在购物车中的物品发生状态变化时每次运行,但是,情况并非如此,我只是不知道为什么。
代码如下:
import {useSelector, useDispatch} from 'react-redux'
import {removeProduct} from '../redux/cart/cart.actions'
import './Cart.scss'
import CartItem from '../components/cartComponent/cartItem'
const mapState = ({ cart }) => ({
itemsInCart: cart.itemsInCart,
total: cart.total
})
const Cart = props => {
const [paidFor, setPaidFor] = useState(false);
const dispatch = useDispatch();
const {itemsInCart} = useSelector(mapState);
const {total} = useSelector(mapState);
let paypalRef = useRef();
const clickHandler = (e) => {
e.preventDefault();
const removeIndex = itemsInCart.findIndex(item => {
return item.id === e.target.id
})
dispatch(removeProduct(removeIndex,itemsInCart[removeIndex]))
}
useEffect(() => {
window.paypal
.Buttons({
createOrder: (data, actions) => {
return actions.order.create({
purchase_units: [
{
description: "product.description",
amount: {
currency_code: 'USD',
value: total,
},
},
],
});
},
onApprove: async (data, actions) => {
const order = await actions.order.capture();
setPaidFor(true);
console.log(order);
},
onError: err => {
setError(err);
console.error(err);
},
})
.render(paypalRef.current);
},[itemsInCart]);
return (
<>
{paidFor ? (
<div><h1>Congrats you just bought an Article</h1></div>
):
<>
<h1>Your Shopping Cart</h1>
<div className = "main">
<form className="cart-area">
<ul className="cart-ui">
{itemsInCart.map((item, index)=> {
return <CartItem
clicked={clickHandler}
name={item.name}
price={item.price}
id={item.id}
key={index}
/>
})}
</ul>
<div className="cart-summary">
<div className ="cart-wrapper">
<div className="name-price-wrapper">
<p className="name">Items</p>
<p className="price">{total}€</p>
</div>
<div ref={paypalRef}></div>
</div>
</div>
</form>
</div>
</>
}
</>
)
}
export default Cart;
当我将useEffect钩子更改为例如总是重新渲染,我会多次获得按钮(取决于我删除的项目数),并且当单击底部的按钮时,它实际上可以使用正确的数量。因此,我必须关闭前面的按钮,因为它们已被渲染。
关注@Preston PHX引用的帖子时,我的代码如下:
useEffect(() => {
if(window.myButton) window.paypal.close();
window.myButton = window.paypal
.Buttons({
createOrder: (data, actions) => {
console.log(total)
return actions.order.create({
purchase_units: [
{
description: "product.description",
amount: {
currency_code: 'USD',
value: total,
},
},
],
});
},
onApprove: async (data, actions) => {
const order = await actions.order.capture();
setPaidFor(true);
console.log(order);
},
onError: err => {
setError(err);
console.error(err);
},
})
.render(paypalRef.current)
});
我在这里收到错误window.myButton.close() is not a function
...?
答案 0 :(得分:1)
您误解了要使用的参数Effect:https://reactjs.org/docs/hooks-effect.html
这将导致效果仅在参数更改后运行
只要参数更改,该效果就不会运行。
如果您确实要重新渲染它们,则另一个可能的问题是关闭现有按钮。如果您的purchase_units对象引用单击按钮时将评估的动态变量/功能,则无需重新渲染它们。但是,如果您要重新渲染按钮,则可能需要关闭现有按钮。您可以通过在对window.PayPal.Buttons(...)进行调用之前存储对window.PayPal.Buttons(...)的引用来执行此操作,以便在定义了.close()之后再进行第二次调用.render之前可以。 >
答案 1 :(得分:0)
import React from "react";
import ReactDOM from "react-dom"
const PayPalButton = paypal.Buttons.driver("react", { React, ReactDOM });
function YourComponent({price}) {
const createOrder = (data, actions) =>{
return actions.order.create({
purchase_units: [
{
amount: {
value: `${price}`,
},
},
],
});
};
const onApprove = (data, actions) => {
return actions.order.capture();
};
return (
<PayPalButton
createOrder={(data, actions) => createOrder(data, actions)}
onApprove={(data, actions) => onApprove(data, actions)}
/>
);
}
Click here for the Paypal documentation
或者尝试使用useRef钩子
import React, { useRef, useEffect } from 'react';
const Paypal = ({ amount }) => {
const paypal = useRef();
useEffect(() => {
if (window.paypalBtn) window.paypalBtn.close();
window.paypalBtn = window.paypal.Buttons({
createOrder: function (data, actions) {
// This function sets up the details of the transaction, including the amount and line item details.
return actions.order.create({
purchase_units: [
{
amount: {
value: `${amount}`,
},
},
],
});
},
onApprove: function (data, actions) {
// This function captures the funds from the transaction.
return actions.order.capture().then(function (details) {
// This function shows a transaction success message to your buyer.
console.log('details', details);
alert('Transaction completed by ' + details.payer.name.given_name);
});
},
onError: function (err) {
console.error(err);
},
});
window.paypalBtn.render(paypal.current);
}, [amount]);
return (
<div>
<div ref={paypal}></div>
</div>
);
};
export default Paypal;