skip to Main Content

I have a modal component in my Next.js project using Radix UI. There are different two way binded inputs using state. The problem is when the state is update the entire page re-renders causing all state to be refreshed. Here is my code:

/* eslint-disable */

"use client";

import * as Dialog from "@radix-ui/react-dialog";
import * as Accordion from "@radix-ui/react-accordion";
import * as sanitizeHtml from "sanitize-html";
import "./components.scss";
import { SetStateAction, useEffect, useRef, useState } from "react";
import useFetch from "@/hooks/useFetch";
import HTTPMethod from "http-method-enum";
import Image from "next/image";
import { loading as loadingImg } from "@/public/icons";
import { Review } from "@/mongo/functions/review";
import { User } from "@/mongo/functions/user";
import Link from "next/link";
import Editor from "react-simple-wysiwyg";
import { expandLess } from "@/public/icons";

export default async function CreateReview({
    userProp,
    type,
    currentUserProp,
    existingReviewProp,
    isSelf,
}: {
    userProp: string;
    type: string;
    currentUserProp: string;
    existingReviewProp: string;
    isSelf: boolean;
}) {
    const existingReview: Review = JSON.parse(existingReviewProp);
    const currentUser: User = JSON.parse(currentUserProp);
    const user: User = JSON.parse(userProp);

    const titleRef = useRef("");
    const [stars, setStars] = useState(5);

    const [html, setHtml] = useState("");

    function onChange(e) {
        setHtml(sanitizeHtml(e.target.value));
    }

    const [wizardText, setWizardText] = useState([]);
    const [wizardOpen, setWizardOpen] = useState(true)

    const [data, setData] = useState(null);
    const [error, setError] = useState("");
    const [loading, setLoading] = useState(false);
    const [deleyed, setDeleyed] = useState(false);
    const [aborted, setAborted] = useState(false);

    useEffect(() => {
        if (!error && !loading && data) {
            window.location.reload();
        }
    }, [data, error, loading]);

    const onSubmit = async (e: any) => {
        e.preventDefault();
        useFetch(setData, setError, setLoading, setDeleyed, aborted, {
            url: "/api/reviews/add",
            method: HTTPMethod.POST,
            body: {
                title: titleRef.current.value,
                stars: stars,
                text: html,
                type: type,
                author: currentUser._id,
                recipient: user._id,
                status: "unlisted",
            },
        });
    };

    const onChecked = (e: any, text: string, id: string) => {
        const wizardTextArray = [...wizardText];

        if (e.target.checked) {
            setHtml(html + text);
        } else if (!e.target.checked) {
            const htmlRegex = new RegExp(
                `<span\s+id=['"]${id}['"][^>]*>.*?<\/span>`,
                "g"
            );
            console.log(htmlRegex);
            console.log(html.replace(htmlRegex, ""));
            setHtml(html.replace(htmlRegex, ""));
        }
    };

    if (isSelf) {
        return (
            <>
                <h1>You can&apos;t write a review for yourself.</h1>
            </>
        );
    }

    if (existingReview) {
        return (
            <>
                <h1>You&apos;ve already writen review for this user.</h1>
            </>
        );
    }

    if (!currentUser.businessName) {
        return (
            <>
                <h1>Setup your business profile to start rating</h1>
                <button className="standard-clr-btn">
                    <Link href="/app/business">Setup</Link>
                </button>
            </>
        );
    }

    const ReviewWizard = () => {
        return (
            <Accordion.Root
                className="AccordionRoot"
                type="single"
                defaultValue="item-1"
                collapsible
            >
                <Accordion.Item className="AccordionItem" value="item-1">
                    <Accordion.Trigger>
                        Review Wizard (Beta)
                        <span className="toggle-open"> Toggle Open</span>
                    </Accordion.Trigger>
                    <Accordion.Content>
                        {stars === 5 ? (
                            <ul>
                                <li>
                                    <input
                                        type="checkbox"
                                        onClick={(e) =>
                                            onChecked(
                                                e,
                                                `<span id="great-work-with">Great to work with! </span>`,
                                                "great-work-with"
                                            )
                                        }
                                    />
                                    <span>Great to work with! </span>
                                </li>
                                <li>
                                    <input
                                        type="checkbox"
                                        onClick={(e) =>
                                            onChecked(
                                                e,
                                                `<span id="loyal-customer">The customer is loyal. </span>`,
                                                "loyal-customer"
                                            )
                                        }
                                    />
                                    <span>The customer is loyal. </span>
                                </li>
                                <li>
                                    <input
                                        type="checkbox"
                                        onClick={(e) =>
                                            onChecked(
                                                e,
                                                `<span id="payed-on-time">The customer payed on time. </span>`,
                                                "payed-on-time"
                                            )
                                        }
                                    />
                                    <span>The customer payed on time. </span>
                                </li>
                            </ul>
                        ) : null}
                        {stars === 4 ? (
                            <ul>
                                <li>
                                    <input
                                        type="checkbox"
                                        onClick={(e) =>
                                            onChecked(
                                                e,
                                                `<span id="loyal-customer">The customer is loyal. </span>`,
                                                "loyal-customer"
                                            )
                                        }
                                    />
                                    <span>The customer is loyal. </span>
                                </li>
                                <li>
                                    <input
                                        type="checkbox"
                                        onClick={(e) =>
                                            onChecked(
                                                e,
                                                `<span id="payed-on-time">The customer paid on time. </span>`,
                                                "payed-on-time"
                                            )
                                        }
                                    />
                                    <span>The customer payed on time. </span>
                                </li>
                                <li>
                                    <input
                                        type="checkbox"
                                        onClick={(e) =>
                                            onChecked(
                                                e,
                                                `<span id="below-average-conditions">The work conditions on the property were below average. </span>`,
                                                "below-average-conditions"
                                            )
                                        }
                                    />
                                    <span>
                                        The work conditions on the property were below average.
                                    </span>
                                </li>
                            </ul>
                        ) : null}
                        {stars === 3 ? (
                            <ul>
                                <li>
                                    <input
                                        type="checkbox"
                                        onClick={(e) =>
                                            onChecked(
                                                e,
                                                `<span id="disloyal-customer">The customer is disloyal. </span>`,
                                                "disloyal-customer"
                                            )
                                        }
                                    />
                                    <span>The customer is disloyal. </span>
                                </li>
                                <li>
                                    <input
                                        type="checkbox"
                                        onClick={(e) =>
                                            onChecked(
                                                e,
                                                `<span id="fault-finding-customer">The customer is fault finding. </span>`,
                                                "fault-finding-customer"
                                            )
                                        }
                                    />
                                    <span>The customer is fault finding. </span>
                                </li>
                                <li>
                                    <input
                                        type="checkbox"
                                        onClick={(e) =>
                                            onChecked(
                                                e,
                                                `<span id="late-pay">The customer did not pay on time. </span>`,
                                                "late-pay"
                                            )
                                        }
                                    />
                                    <span>The customer did not pay on time. </span>
                                </li>
                                <li>
                                    <input
                                        type="checkbox"
                                        onClick={(e) =>
                                            onChecked(
                                                e,
                                                `<span id="payed-on-time">The customer paid on time. </span>`,
                                                "payed-on-time"
                                            )
                                        }
                                    />
                                    <span>The customer payed on time. </span>
                                </li>
                                <li>
                                    <input
                                        type="checkbox"
                                        onClick={(e) =>
                                            onChecked(
                                                e,
                                                `<span id="below-average-conditions">The work conditions on the property were below average. </span>`,
                                                "below-average-conditions"
                                            )
                                        }
                                    />
                                    <span>
                                        The work conditions on the property were below average.
                                    </span>
                                </li>
                            </ul>
                        ) : null}
                        {stars === 2 ? (
                            <ul>
                                <li>
                                    <input
                                        type="checkbox"
                                        onClick={(e) =>
                                            onChecked(
                                                e,
                                                `<span id="disloyal-customer">The customer is disloyal. </span>`,
                                                "disloyal-customer"
                                            )
                                        }
                                    />
                                    <span>The customer is disloyal. </span>
                                </li>
                                <li>
                                    <input
                                        type="checkbox"
                                        onClick={(e) =>
                                            onChecked(
                                                e,
                                                `<span id="fault-finding-customer">The customer is fault finding. </span>`,
                                                "fault-finding-customer"
                                            )
                                        }
                                    />
                                    <span>The customer is fault finding. </span>
                                </li>
                                <li>
                                    <input
                                        type="checkbox"
                                        onClick={(e) =>
                                            onChecked(
                                                e,
                                                `<span id="late-pay">The customer did not pay on time. </span>`,
                                                "late-pay"
                                            )
                                        }
                                    />
                                    <span>The customer did not pay on time. </span>
                                </li>
                                <li>
                                    <input
                                        type="checkbox"
                                        onClick={(e) =>
                                            onChecked(
                                                e,
                                                `<span id="below-average-conditions">The work conditions on the property were below average. </span>`,
                                                "below-average-conditions"
                                            )
                                        }
                                    />
                                    <span>
                                        The work conditions on the property were below average.
                                    </span>
                                </li>
                            </ul>
                        ) : null}
                        {stars === 1 ? (
                            <ul>
                                <li>
                                    <input
                                        type="checkbox"
                                        onClick={(e) =>
                                            onChecked(
                                                e,
                                                `<span id="disloyal-customer">The customer is disloyal. </span>`,
                                                "disloyal-customer"
                                            )
                                        }
                                    />
                                    <span>The customer is disloyal. </span>
                                </li>
                                <li>
                                    <input
                                        type="checkbox"
                                        onClick={(e) =>
                                            onChecked(
                                                e,
                                                `<span id="fault-finding-customer">The customer is fault finding. </span>`,
                                                "fault-finding-customer"
                                            )
                                        }
                                    />
                                    <span>The customer is fault finding. </span>
                                </li>
                                <li>
                                    <input
                                        type="checkbox"
                                        onClick={(e) =>
                                            onChecked(
                                                e,
                                                `<span id="no-pay">The customer did not pay. </span>`,
                                                "no-pay"
                                            )
                                        }
                                    />
                                    <span>The customer did not pay. </span>
                                </li>
                                <li>
                                    <input
                                        type="checkbox"
                                        onClick={(e) =>
                                            onChecked(
                                                e,
                                                `<span id="below-average-conditions">The work conditions on the property were below average. </span>`,
                                                "below-average-conditions"
                                            )
                                        }
                                    />
                                    <span>
                                        The work conditions on the property were below average.
                                    </span>
                                </li>
                            </ul>
                        ) : null}
                    </Accordion.Content>
                </Accordion.Item>
            </Accordion.Root>
        );
    };

    return (
        <Dialog.Root>
            <Dialog.Trigger asChild>
                <button className="standard-clr-btn" style={{ height: 50 }}>
                    Write a review
                </button>
            </Dialog.Trigger>
            <Dialog.Portal>
                <Dialog.Overlay className="DialogOverlay" />
                <Dialog.Content className="DialogContent standard-dialog">
                    {currentUser.isBetaUser ? <ReviewWizard /> : null}
                    {loading && !error ? (
                        <>
                            <Image
                                src={loadingImg}
                                alt="Loading..."
                                className="popup-loading"
                            />
                            {deleyed ? (
                                <div>
                                    <h1>Your request is taking longer than usual</h1>
                                    <p>
                                        We are still working to complete it. You can cancel this
                                        request and try again if you like. Note you will lose any
                                        data you submited.
                                    </p>
                                    <button
                                        onClick={() => setAborted(true)}
                                        className="standard-clr-btn"
                                    >
                                        Cancel
                                    </button>
                                </div>
                            ) : null}
                        </>
                    ) : (
                        <form onSubmit={(e) => onSubmit(e)}>
                            {error ? <span className="error-text">{error} </span> : null}
                            <label>How many stars?</label>
                            <select
                                value={stars}
                                onChange={(e) => setStars(Number(e.target.value))}
                                className="standard-dropdown"
                            >
                                <option value={1}>1 star</option>
                                <option value={2}>2 stars</option>
                                <option value={3}>3 stars</option>
                                <option value={4}>4 stars</option>
                                <option value={5} selected>
                                    5 stars
                                </option>
                            </select>
                            <label>What&apos;s your title?</label>
                            <input
                                className="standard-input"
                                name="title"
                                ref={titleRef}
                                placeholder="Great to work with!"
                            />
                            <label>What do you want to say?</label>
                            <Editor value={html} onChange={onChange} />
                            <button
                                className="standard-clr-btn"
                                aria-label="Send"
                                type="submit"
                                style={{ height: 50 }}
                            >
                                Publish
                            </button>
                        </form>
                    )}
                    <Dialog.Close asChild>
                        <button className="IconButton" aria-label="Close">
                            Close
                        </button>
                    </Dialog.Close>
                </Dialog.Content>
            </Dialog.Portal>
        </Dialog.Root>
    );
}

The strange thing is the refs aren’t causing the entire page to render just the areas with state.

2

Answers


  1. Chosen as BEST ANSWER

    The issue was the async part of the client component.


  2. Using window.location.reload(); in a single page application such as React.js defeats the purpose of why Single Page Applications were created in the first place, consider removing it. Any update to the following states data, error, loading used as deps for the useEffect will cause your window to reload and this in turn resets all your application state.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search