如何在React Redux中混合使用全局状态和本地状态

时间:2020-05-22 21:39:27

标签: reactjs redux react-redux state

我有一个产品页面,其中maps遍历所有产品,并分别显示产品图片和“添加到购物车”按钮。

在添加到购物车点击后,我从我的redux操作中调用了一个函数。该函数将一个API请求发送到后端。通话进行中,我想用加载程序替换“添加到购物车”按钮。

在我的redux cart状态下,有一个布尔属性cartLoading,该属性在调用开始时设置为true,在调用解决后设置为false。这是问题所在:如果在我的EachProduct组件中,我将天气的逻辑或不显示装载程序绑定到购物车状态的cartLoading的值,那么发生的是所有“添加到购物车”由于cartLoading是全局状态属性,因此页面上的'按钮已替换为加载程序。但是我也无法使用useState加载本地状态,因为我无法知道组件天气范围内对后端的调用是否已经完成,因为它是通过全局操作功能完成的。

我尝试将subscribe移至store,并在单击按钮时监听cartLoading属性的变化,但是由于我不知道组件范围何时通话结束,我不知道什么时候取消订阅。所以发生了什么事,当我在第一个项目上单击“添加到购物车”时,它工作正常,只有那个项目正在显示装载程序。但是然后,当我单击另一个项目时,第一个和第二个都显示了加载程序,因为第一个和第二个现在已订阅了全局cartLoading状态,而第一个从未取消订阅。

我也尝试了以下代码,但是没有显示任何加载器:

const [loading, setLoading] = useState(false);

  const [unsubscribe, setUnsubscribe] = useState(null);

  const onSubmit = (e, variantToken) => {
    e.preventDefault();

    const subscribeToCartLoadingState = () => {
      let loading = store.getState().cart.cartLoading;
      setLoading(loading);
    };

    setUnsubscribe(store.subscribe(subscribeToCartLoadingState));

    addProductToCart(
      {
        prodToken: variantToken,
        cartProdQuantity: 1,
      },
      cartToken
    );
  };

  useEffect(() => {
    console.log(unsubscribe);

    if (!cartLoading && unsubscribe) unsubscribe();
  }, [cartLoading]);

然后是我的jsx中的按钮:

!loading ? (
           { <button
              type="button"
              onClick={(e) => onSubmit(e, product.variants[0].variantToken)}
              className="btn waves-effect blue"
            >
              Add to cart
            </button>
          ) : (
            <MiniSpinner />
          )}

对此有任何解决方法吗?是唯一在本地发出后端请求的选项吗?

P.s。如果您对此问题的标题更好,请随时进行编辑。

2 个答案:

答案 0 :(得分:1)

正如我在评论中提到的那样,如果您重构redux状态以指定要专门加载的项目,那么我认为您将万事如意。这样一来,您就不必真正担心调和全球和本地状态。

如果您打算使用当前的状态设置,那么我认为如果没有创建的subscribe函数,以下内容可能会起作用。基本上,您可以在分派操作时将本地loading的状态设置为true。由于您已经cartLoading从redux进行了迁移,因此您只需要一种效果,该效果会在更改后运行,并将本地loading的状态翻转回false

const [loading, setLoading] = useState(false);

const onSubmit = (e, variantToken) => {
  e.preventDefault();
  setLoading(true);
  addProductToCart(
    {
      prodToken: variantToken,
      cartProdQuantity: 1,
    },
    cartToken
  );
};

useEffect(() => {
  if (!cartLoading && loading) setLoading(false);
}, [cartLoading]);

答案 1 :(得分:0)

也许您可以使用:

https://github.com/RisingStack/react-easy-state

https://github.com/ctrlplusb/easy-peasy

他们可以管理全球和本地商店。