Next JS Judge Me Integration
Unanswered
Cornish Rex posted this in #help-forum
Cornish RexOP
Hello. I integrated Judge.me into Shopify at the request of my customer. In this project, we are transferring data from Shopify to Next JS with the Storefront API. Judge.me allows me to add review data to the page via a few scripts and a div. But there is one problem. Sometimes this data is not visible when loading the page. For this reason, it is necessary to refresh the page. Sometimes after repeating this a few times, I am able to view the data. When I asked them about this situation, they mentioned that it could be due to the nature of React.
In this case, I was looking for a solution. At first, I added a Head component to this component and included the scripts with the script tag. But this naturally caused the Hydration issue. Then, when I wanted to add these codes to the Head part of _app.js or the pages where this component was called, I could see the data for 1 second and then quickly disappeared. That's why I tried to use the codes in the Scrpit component in the same component. But this time, the review data did not appear more often, or the review comments did not appear even though the content of Judge.me was visible.
And finally, I wrote the scripts (as you'll see in the code below) as a function, and it has obviously worked best. But in this method, sometimes the div belonging to Judge.me does not appear on the page at all.
So I decided to do a height control as a solution. If the height of the section tag is below 550px, I wrote codes to accept that the data has not arrived and make the component reload. But that didn't quite work either. There was no change.
In the codes I wrote before, if the section is under 550px, I tried a method so that the page is completely refreshed and it automatically comes to the current position on the page thanks to state. But frankly, this method was very disturbing to me.
+++ Please see the comments section for more.
In this case, I was looking for a solution. At first, I added a Head component to this component and included the scripts with the script tag. But this naturally caused the Hydration issue. Then, when I wanted to add these codes to the Head part of _app.js or the pages where this component was called, I could see the data for 1 second and then quickly disappeared. That's why I tried to use the codes in the Scrpit component in the same component. But this time, the review data did not appear more often, or the review comments did not appear even though the content of Judge.me was visible.
And finally, I wrote the scripts (as you'll see in the code below) as a function, and it has obviously worked best. But in this method, sometimes the div belonging to Judge.me does not appear on the page at all.
So I decided to do a height control as a solution. If the height of the section tag is below 550px, I wrote codes to accept that the data has not arrived and make the component reload. But that didn't quite work either. There was no change.
In the codes I wrote before, if the section is under 550px, I tried a method so that the page is completely refreshed and it automatically comes to the current position on the page thanks to state. But frankly, this method was very disturbing to me.
+++ Please see the comments section for more.
3 Replies
Cornish RexOP
My only purpose is to do something like this: In the foreground, if the data provided by the scripts did not come to the div, the text "Reviews Data Is Loading" should be displayed. And in the background, I want it to try every 3 seconds so that the section size reaches 550px. If the section height is 550px in the background, I want the text "Reviews Data Is Loading" to disappear and the review data to appear. And while this is happening, the page should not be fully refreshed. Only the component should be updated. Is there any way to achieve this?
Or is there a way I can directly get the scripts to work for sure?
Here are my codes:
Or is there a way I can directly get the scripts to work for sure?
Here are my codes:
import React, { useRef, useState, useEffect } from "react";
import styles from "./JudgeMeReviews.module.scss";
import { themes } from "@/components/ThemeContext";
import classnames from "classnames";
import Head from "next/head";
import { useInView } from "react-intersection-observer";
import Script from "next/script";
import { useRouter } from "next/router";
const JudgeMeReviews = ({ theme, data }) => {
const { ref, entry } = useInView({
threshold: 0,
triggerOnce: true,
});
const isScriptLoadedRef = useRef(false);
useEffect(() => {
if (entry && !isScriptLoadedRef.current) {
isScriptLoadedRef.current = true;
loadScripts();
}
}, [entry]);
const [isLoading, setIsLoading] = useState(true);
const [isContentVisible, setIsContentVisible] = useState(false);
const sectionRef = useRef(null);
useEffect(() => {
const handleResize = () => {
if (sectionRef.current.offsetHeight < 550) {
setIsContentVisible(false);
setIsLoading(true);
loadScripts();
} else {
setIsContentVisible(true);
setIsLoading(false);
}
};
const interval = setInterval(handleResize, 3000);
handleResize();
window.addEventListener("resize", handleResize);
return () => {
clearInterval(interval);
window.removeEventListener("resize", handleResize);
};
}, []);
import styles from "./JudgeMeReviews.module.scss";
import { themes } from "@/components/ThemeContext";
import classnames from "classnames";
import Head from "next/head";
import { useInView } from "react-intersection-observer";
import Script from "next/script";
import { useRouter } from "next/router";
const JudgeMeReviews = ({ theme, data }) => {
const { ref, entry } = useInView({
threshold: 0,
triggerOnce: true,
});
const isScriptLoadedRef = useRef(false);
useEffect(() => {
if (entry && !isScriptLoadedRef.current) {
isScriptLoadedRef.current = true;
loadScripts();
}
}, [entry]);
const [isLoading, setIsLoading] = useState(true);
const [isContentVisible, setIsContentVisible] = useState(false);
const sectionRef = useRef(null);
useEffect(() => {
const handleResize = () => {
if (sectionRef.current.offsetHeight < 550) {
setIsContentVisible(false);
setIsLoading(true);
loadScripts();
} else {
setIsContentVisible(true);
setIsLoading(false);
}
};
const interval = setInterval(handleResize, 3000);
handleResize();
window.addEventListener("resize", handleResize);
return () => {
clearInterval(interval);
window.removeEventListener("resize", handleResize);
};
}, []);
const loadScripts = () => {
const script1 = document.createElement("script");
script1.innerHTML =
document.head.appendChild(script1);
const script2 = document.createElement("script");
script2.src = "https://cdn.judge.me/widget_preloader.js";
script2.async = true;
script2.setAttribute("data-cfasync", "false");
document.head.appendChild(script2);
const script3 = document.createElement("script");
script3.src = "https://cdn1.judge.me/assets/installed.js";
script3.async = true;
script3.setAttribute("data-cfasync", "false");
document.head.appendChild(script3);
};
return (
<section
className={classnames(
styles.section,
"reviews",
theme === themes.dark ? "dark" : "light"
)}
ref={sectionRef}
>
<span
className={
></span>
<h2
className={classnames("title-1", styles.title)}
style={{ color: theme?.titleColor }}
>
Reviews
</h2>
{isLoading && "Reviews Data Is Loading..."}
<div
// class="jdgm-widget jdgm-review-widget jdgm-outside-widget"
className={classnames("widget jdgm-review-widget jdgm-outside-widget", {
[styles.hidden]: isLoading || !isContentVisible,
})}
data-id="myid"
data-product-title="myproduct"
></div>
</section>
);
};
export default JudgeMeReviews;
const script1 = document.createElement("script");
script1.innerHTML =
jdgm = window.jdgm || {};
jdgm.SHOP_DOMAIN = 'myshop';
jdgm.PLATFORM = 'shopify';
jdgm.PUBLIC_TOKEN = 'mytoken';;document.head.appendChild(script1);
const script2 = document.createElement("script");
script2.src = "https://cdn.judge.me/widget_preloader.js";
script2.async = true;
script2.setAttribute("data-cfasync", "false");
document.head.appendChild(script2);
const script3 = document.createElement("script");
script3.src = "https://cdn1.judge.me/assets/installed.js";
script3.async = true;
script3.setAttribute("data-cfasync", "false");
document.head.appendChild(script3);
};
return (
<section
className={classnames(
styles.section,
"reviews",
theme === themes.dark ? "dark" : "light"
)}
ref={sectionRef}
>
<span
className={
line line-top ${entry?.isIntersecting ? "line-isInView" : ""
}}></span>
<h2
className={classnames("title-1", styles.title)}
style={{ color: theme?.titleColor }}
>
Reviews
</h2>
{isLoading && "Reviews Data Is Loading..."}
<div
// class="jdgm-widget jdgm-review-widget jdgm-outside-widget"
className={classnames("widget jdgm-review-widget jdgm-outside-widget", {
[styles.hidden]: isLoading || !isContentVisible,
})}
data-id="myid"
data-product-title="myproduct"
></div>
</section>
);
};
export default JudgeMeReviews;