Shopify / ui-extensions

MIT License
269 stars 35 forks source link

Checkout UI Extension Re-rendering Causing Poor UX #2459

Open kalpitrathore1 opened 2 weeks ago

kalpitrathore1 commented 2 weeks ago

Hello guys,

I'm encountering an issue with the checkout UI extensions where my extension point is being re-rendered multiple times. This behavior is impacting the user experience for my app, as the unnecessary re-renders cause a disruptive interface.

I've attached the code snippet and a video for better visualization.


Code Overview

The main functionality here involves a React component within a Shopify app, designed to render some UI before the shipping options list during checkout. The component, Print, uses Shopify's useShippingAddress hook to access the current shipping address. When the shipping address changes, the Print component is intended to log a message to the console.

However, due to frequent re-renders, the console.log in the Print component’s useEffect hook is firing multiple times. This re-rendering issue creates unwanted logging and impacts the app's UX by making the interface feel less stable or responsive.

Code Snippet

address.jsx

import { useEffect } from "react";
import {
  View,
  useShippingAddress,
  reactExtension,
} from "@shopify/ui-extensions-react/checkout";

// This component renders content before the shipping options list in checkout
const shippingRender = reactExtension(
  "purchase.checkout.shipping-option-list.render-before",
  () => (
    <View>
      <Print />
    </View>
  )
);

// The Print component, which logs shipping address updates
export function Print() {
  const shippingAddress = useShippingAddress();

  // useEffect logs a message every time the shipping address changes
  useEffect(() => {
    console.log('console getting loaded multiple times');
  }, [shippingAddress]);

  return null;
}

package.json

{
  "name": "shopify app",
  "private": true,
  "scripts": {
    "build": "NODE_ENV=production remix build",
    "predev": "prisma generate && prisma migrate deploy",
    "dev": "shopify app dev",
    "config:link": "shopify app config link",
    "config:push": "shopify app config push",
    "generate": "shopify app generate",
    "deploy": "shopify app deploy",
    "config:use": "shopify app config use",
    "env": "shopify app env",
    "start": "remix-serve build",
    "lint": "eslint --cache --cache-location ./node_modules/.cache/eslint .",
    "shopify": "shopify",
    "prisma": "prisma",
    "setup": "prisma generate && prisma migrate deploy"
  },
  "dependencies": {
    "@prisma/client": "4.13.0",
    "@remix-run/node": "1.19.1",
    "@remix-run/react": "1.19.1",
    "@remix-run/serve": "1.19.1",
    "@shopify/app": "3.57.1",
    "@shopify/app-bridge-types": "0.0.2",
    "@shopify/cli": "3.57.1",
    "@shopify/polaris": "11.1.2",
    "@shopify/shopify-app-remix": "1.0.3",
    "@shopify/shopify-app-session-storage-prisma": "1.0.0",
    "cross-env": "7.0.3",
    "ejs": "3.1.9",
    "isbot": "latest",
    "prisma": "4.13.0",
    "react": "18.2.0",
    "react-dom": "18.2.0"
  },
  "devDependencies": {
    "@remix-run/dev": "1.19.1",
    "@remix-run/eslint-config": "1.19.1",
    "@types/eslint": "8.40.0",
    "eslint": "8.42.0",
    "eslint-config-prettier": "8.8.0",
    "prettier": "2.8.8"
  },
  "workspaces": [
    "web",
    "web/frontend",
    "extensions/*"
  ]
}

video.mp4 https://github.com/user-attachments/assets/1dde486e-ecc7-4eb0-9a5f-622c0342ccc2

If you see in the video above, Console is getting printed 6 times

developerdevit commented 2 weeks ago

+1 to this one! In my case, my console.log() is just placed at the start of component and also gets printed multiple times:

export default reactExtension('purchase.checkout.block.render', () => <Component />)

const Component = () => {
    console.log('ENTRY POINT')
    return <></>
}

Just wondering if it's a bug or I'm missing something

developerdevit commented 2 weeks ago

A little update: after I completely removed every hook from a component it now renders only once. I guess in my case it might be a Shopify's useCartLines() hook that:

Returns the current line items for the checkout, and automatically re-renders your component if line items are added, removed, or updated.

So my advice to go through your hooks to see if this is actually intended

kalpitrathore1 commented 2 weeks ago

A little update: after I completely removed every hook from a component it now renders only once. I guess in my case it might be a Shopify's useCartLines() hook that:

Returns the current line items for the checkout, and automatically re-renders your component if line items are added, removed, or updated.

So my advice to go through your hooks to see if this is actually intended

Hey @developerdevit

We need access to shipping addresses for specific use cases, so we've implemented hooks to manage this so can't remove them.