0

What I want to do

to load the SG page generated at build time in the CSR page.

app/
  SG/[id]/product/page.tsx
  CSR/page.tsx

(Next version is 14)

The HTML output file of the CSR is assumed to be as follows

  <div data-id="product1">
   // SG content
  </div>

This is similar to a CSR application implemented in regular React:

  <div id="root" data-id="product1"></div>
  <script src="..."></script>

In short, I want to replace the components under the div that were dynamically running in CSR with HTML statically built by Next.js.

I assume we need to implement a client js that switches the static HTML depending on the data attribute set in the div tag, how can we accomplish this?

1 Answer 1

0

Finally, we were able to display something CSR-like by displaying Next.js static HTML over Iframe (Note that it is assumed that it is of the same origin).

parent HTML:

<div id="target" data-id="product1"></div>
<script "src="/js/loadIframe.js></script>


js for calling iframe:

(function () {
  
  const embedTarget = document.getElementById('target');
  if(!embedTarget) {
    throw new Error('Not found target element');
  }
  const productId = embedTarget.getAttribute('data-id');
  if(!productId) {
    throw new Error('Not specified product ID');
  }

  const iframe = document.createElement('iframe');
  const iframeSrc = `/assets/products/${productId}.html`
  iframe.id = 'iframeId';
  iframe.src = iframeSrc;
  iframe.style.width = '100%';
  iframe.style.overflow = 'hidden';
  iframe.scrolling = 'no';

  iframe.onload = function () {
    iframe.contentWindow.postMessage({
      type: 'MESSAGE_FROM_PARENT_HTML',
      data: { productId },
    });
  };
  embedTarget.appendChild(iframe);

})();

Next.js(Client Component Root):

'use client';

import { ReactNode, useCallback, useEffect, useState } from 'react';


interface MessageDataProps {
  productId: string;
}

interface OwnProps {
  children: ReactNode;
}

export function ClientComponent({ children }: OwnProps) {
  const [messageData, setMessageData] = useState<MessageDataProps>();


  const receiveMessage = useCallback(
    (event: MessageEvent<{ type: string; data: HTMLPartsDataProps }>) => {
      const response = event.data;
      if (response.type === 'MESSAGE_FROM_PARENT_HTML') {
        setMessageData(response.data);
      }
    },
    []
  );

  useEffect(() => {
    if (typeof window === 'object') {
      window.addEventListener('message', receiveMessage);
    }
    return () => window.removeEventListener('message', receiveMessage);
  }, [messageData]);

  if (messageData) {
    return (
      <div
        ref={ref}
        data-id={messageData.productId}
      >{children}
      </div>
    );
  }

}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.