skip to Main Content
import React, { useEffect, useState } from "react";
import styled from "styled-components";
import arcade from "../assets/images/icon-arcade.svg";
import advanced from "../assets/images/icon-advanced.svg";
import pro from "../assets/images/icon-pro.svg";

const SelectYourPlan = () => {
  const [toggle, setToggle] = useState(0);
  const [init, setInit] = useState(true);
  useEffect(() => {
    console.log(toggle);
    console.log(init);
    if (toggle === 0) {
      document.getElementsByClassName("ball")[0].style.marginLeft = "0vw";
      document.getElementById("left").style.color = "hsl(213, 96%, 18%)";
      document.getElementById("right").style.color = "hsl(231, 11%, 63%)";

      if (init === false) {
        let arcade = document.getElementsByClassName("arcade")[0];
        let advanced = document.getElementsByClassName("advanced")[0];
        let pro = document.getElementsByClassName("pro")[0];

        let arcadePrice = document.getElementById("arcadePrice");
        let advancedPrice = document.getElementById("advancedPrice");
        let proPrice = document.getElementById("proPrice");

        arcadePrice.textContent = "$9/month";
        advancedPrice.textContent = "$12/month";
        proPrice.textContent = "$15/month";

        arcade.removeChild(arcade.lastElementChild);
        advanced.removeChild(advanced.lastElementChild);
        pro.removeChild(pro.lastElementChild);
      }
    } else {
      let extraContentElement = document.createElement("p");
      extraContentElement.textContent = "2 months free";

      let arcade = document.getElementsByClassName("arcade")[0];
      let advanced = document.getElementsByClassName("advanced")[0];
      let pro = document.getElementsByClassName("pro")[0];

      let arcadePrice = document.getElementById("arcadePrice");
      let advancedPrice = document.getElementById("advancedPrice");
      let proPrice = document.getElementById("proPrice");

      arcadePrice.textContent = "$90/year";
      advancedPrice.textContent = "$120/year";
      proPrice.textContent = "$150/year";

      arcade.appendChild(extraContentElement.cloneNode(true));
      advanced.appendChild(extraContentElement.cloneNode(true));
      pro.appendChild(extraContentElement.cloneNode(true));

      arcade.lastElementChild.id = "arcade-free";
      advanced.lastElementChild.id = "advanced-free";
      pro.lastElementChild.id = "pro-free";

      document.getElementsByClassName("ball")[0].style.marginLeft = "1vw";
      document.getElementById("right").style.color = "hsl(213, 96%, 18%)";
      document.getElementById("left").style.color = "hsl(231, 11%, 63%)";
    }
  }, [toggle]);
  const handleClick = () => {
    if (toggle === 0) {
      setToggle(1);
      setInit(false);
    } else {
      setToggle(0);
    }
  };
  return (
    <Container>
      <h1> Select your plan</h1>
      <Subtitle>You have the option of monthly or yearly billing.</Subtitle>
      <Flex>
        <Arcade imgUrl={arcade} className="arcade">
          <Title>Arcade</Title> <Price id="arcadePrice">$9/mo</Price>
        </Arcade>
        <Advanced imgUrl={advanced} className="advanced">
          <Title>Advanced</Title>
          <Price id="advancedPrice">$12/mo</Price>
        </Advanced>
        <Pro imgUrl={pro} className="pro">
          <Title>Pro</Title>
          <Price id="proPrice">$15/mo</Price>
        </Pro>
      </Flex>
      <SwitchBar>
        <Left id="left">Monthly</Left>
        <Switch onClick={handleClick}>
          <Ball className="ball"></Ball>
        </Switch>
        <Right id="right">Yearly</Right>
      </SwitchBar>
      <GoBack>Go Back</GoBack>
      <Next>Next Step</Next>
    </Container>
  );
};

Actually I have a toggle switch whenever I click on that (when toggle state becomes 1) I want a extra sentence to display at the last in each of ‘arcade’,’advanced’,’pro’ components. This works fine but when I make some changes and save the file on the same toggle position (toggle=1) the statements keep on adding. If I do this on toggle=0 they start to get deleted as per the code. Maybe this is because the page re-renders on saving but is there any way to stop this as this poses great problem in debugging.

2

Answers


  1. You can use React’s state management keeping track of added elements and only add/remove as needed when toggle changes.

    Something like this as reference, do adapt to your code, this is only an example.

    const [addedElements, setAddedElements] = useState([]);
    
    useEffect(() => {
      if (toggle === 0) {
        document.getElementsByClassName("ball")[0].style.marginLeft = "0vw";
        document.getElementById("left").style.color = "hsl(213, 96%, 18%)";
        document.getElementById("right").style.color = "hsl(231, 11%, 63%)";
    
        if (init === false) {
          let arcade = document.getElementsByClassName("arcade")[0];
          let advanced = document.getElementsByClassName("advanced")[0];
          let pro = document.getElementsByClassName("pro")[0];
    
          let arcadePrice = document.getElementById("arcadePrice");
          let advancedPrice = document.getElementById("advancedPrice");
          let proPrice = document.getElementById("proPrice");
    
          arcadePrice.textContent = "$9/month";
          advancedPrice.textContent = "$12/month";
          proPrice.textContent = "$15/month";
    
          // Only remove elements if they were added before
          if (addedElements.includes("arcade-free")) {
            arcade.removeChild(document.getElementById("arcade-free"));
          }
          if (addedElements.includes("advanced-free")) {
            advanced.removeChild(document.getElementById("advanced-free"));
          }
          if (addedElements.includes("pro-free")) {
            pro.removeChild(document.getElementById("pro-free"));
          }
        }
      } else {
        let extraContentElement = document.createElement("p");
        extraContentElement.textContent = "2 months free";
    
        let arcade = document.getElementsByClassName("arcade")[0];
        let advanced = document.getElementsByClassName("advanced")[0];
        let pro = document.getElementsByClassName("pro")[0];
    
        let arcadePrice = document.getElementById("arcadePrice");
        let advancedPrice = document.getElementById("advancedPrice");
        let proPrice = document.getElementById("proPrice");
    
        arcadePrice.textContent = "$90/year";
        advancedPrice.textContent = "$120/year";
        proPrice.textContent = "$150/year";
    
        // Only add elements if they haven't been added before
        if (!addedElements.includes("arcade-free")) {
          arcade.appendChild(extraContentElement.cloneNode(true));
          arcade.lastElementChild.id = "arcade-free";
          setAddedElements(prevAddedElements => [...prevAddedElements, "arcade-free"]);
        }
        if (!addedElements.includes("advanced-free")) {
          advanced.appendChild(extraContentElement.cloneNode(true));
          advanced.lastElementChild.id = "advanced-free";
    

    Edit: Since this is not how you should be using React, here is an example of how to properly use React state to store the prices and render them

    const [prices, setPrices] = useState({
      arcade: "$9/month",
      advanced: "$12/month",
      pro: "$15/month"
    });
    
    useEffect(() => {
      if (toggle === 1) {
        setPrices({
          arcade: "$90/year",
          advanced: "$120/year",
          pro: "$150/year"
        });
      } else {
        setPrices({
          arcade: "$9/month",
          advanced: "$12/month",
          pro: "$15/month"
        });
      }
    }, [toggle]);
    
    ...
    
    <Arcade imgUrl={arcade} className="arcade">
      <Title>Arcade</Title>
      <Price>{prices.arcade}</Price>
    </Arcade>
    <Advanced imgUrl={advanced} className="advanced">
      <Title>Advanced</Title>
      <Price>{prices.advanced}</Price>
    </Advanced>
    <Pro imgUrl={pro} className="pro">
      <Title>Pro</Title>
      <Price>{prices.pro}</Price>
    </Pro>
    
    Login or Signup to reply.
  2. You seem to completely misunderstand the way React is meant to be used. You should not use id, class, or any of getElementsByClassName, getElementById, style, textContent, removeChild, createElement, cloneNode, etc.

    Instead you should simply return something different depending on the current state and let React deal with DOM manipulation. Here is a cleaned up version of your code.
    Note that we’re simply returning different things depending on whether showYearly is true or false.
    I renamed toggle to showYearly for clarity and removed init as I have no idea what it’s meant to do.

    import React, { useEffect, useState } from "react";
    import styled from "styled-components";
    import arcade from "../assets/images/icon-arcade.svg";
    import advanced from "../assets/images/icon-advanced.svg";
    import pro from "../assets/images/icon-pro.svg";
    
    const SelectYourPlan = () => {
      const [showYearly, setShowYearly] = useState(false);
      const handleClick = () => {
        setShowYearly(showYearly => !showYearly);
      };
      return (
        <Container>
          <h1> Select your plan</h1>
          <Subtitle>You have the option of monthly or yearly billing.</Subtitle>
          <Flex>
            <Arcade imgUrl={arcade}>
              <Title>Arcade</Title>
              <Price>{showYearly ? "$90/year" : "$9/mo"}</Price>
              {showYearly && <p>2 months free</p>}
            </Arcade>
            <Advanced imgUrl={advanced}>
              <Title>Advanced</Title>
              <Price>{showYearly ? "$120/year" : "$12/mo"}</Price>
              {showYearly && <p>2 months free</p>}
            </Advanced>
            <Pro imgUrl={pro}>
              <Title>Pro</Title>
              <Price>{showYearly ? "$150/year" : "$15/mo"}</Price>
              {showYearly && <p>2 months free</p>}
            </Pro>
          </Flex>
          <SwitchBar>
            <Left $showYearly={showYearly}>Monthly</Left>
            <Switch onClick={handleClick}>
              <Ball $showYearly={showYearly}/>
            </Switch>
            <Right $showYearly={showYearly}>Yearly</Right>
          </SwitchBar>
          <GoBack>Go Back</GoBack>
          <Next>Next Step</Next>
        </Container>
      );
    };
    

    For the style on Left, Right and Ball, you should use transient props from styled-components. For instance:

    const Left = styled.div`
      color: ${props => props.$showYearly ? "hsl(213, 96%, 18%)" : "hsl(231, 11%, 63%)"};
      [...]
    `;
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search