英文:
file rerendering on save
问题
以下是您提供的代码的翻译部分,代码部分不被翻译:
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>
);
};
关于您的问题,每次您保存文件时,组件会重新渲染,因此导致额外的语句不断添加。为了解决这个问题,您可以使用 useEffect
钩子来清除先前的额外语句,以确保只有一个额外语句被添加。在 useEffect
中,您可以添加逻辑,检查是否已经存在额外语句,如果存在,则先将其删除,然后再添加新的额外语句。这样可以确保只有一个额外语句存在。
英文:
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.
答案1
得分: 2
你似乎完全误解了React的使用方式。您不应该使用id
、class
或任何getElementsByClassName
、getElementById
、style
、textContent
、removeChild
、createElement
、cloneNode
等。
相反,您应该根据当前状态返回不同的内容,让React处理DOM操作。以下是您代码的清理版本。
请注意,我们只是根据showYearly
是true还是false返回不同的东西。
我将toggle
重命名为showYearly
以增加清晰度,并删除了init
,因为我不知道它的用途。
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>选择您的计划</h1>
<Subtitle>您可以选择按月或按年计费。</Subtitle>
<Flex>
<Arcade imgUrl={arcade}>
<Title>Arcade</Title>
<Price>{showYearly ? "$90/year" : "$9/mo"}</Price>
{showYearly && <p>2个月免费</p>}
</Arcade>
<Advanced imgUrl={advanced}>
<Title>Advanced</Title>
<Price>{showYearly ? "$120/year" : "$12/mo"}</Price>
{showYearly && <p>2个月免费</p>}
</Advanced>
<Pro imgUrl={pro}>
<Title>Pro</Title>
<Price>{showYearly ? "$150/year" : "$15/mo"}</Price>
{showYearly && <p>2个月免费</p>}
</Pro>
</Flex>
<SwitchBar>
<Left $showYearly={showYearly}>每月</Left>
<Switch onClick={handleClick}>
<Ball $showYearly={showYearly}/>
</Switch>
<Right $showYearly={showYearly}>每年</Right>
</SwitchBar>
<GoBack>返回</GoBack>
<Next>下一步</Next>
</Container>
);
};
对于Left
、Right
和Ball
的样式,您应该使用styled-components
中的临时属性。例如:
const Left = styled.div`
color: ${props => props.$showYearly ? "hsl(213, 96%, 18%)" : "hsl(231, 11%, 63%)"};
[...]
`;
英文:
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%)"};
[...]
`;
答案2
得分: 0
你可以使用React的状态管理来跟踪已添加的元素,并根据需要添加或移除元素。
类似以下的示例,根据你的代码进行调整,这只是一个示例:
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";
// 只有在之前已经添加的情况下才移除元素
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";
// 只有在之前未添加的情况下才添加元素
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";
setAddedElements(prevAddedElements => [...prevAddedElements, "advanced-free"]);
}
}
}
请注意,这只是一个示例,使用React的状态管理通常更好,如下面示例所示。
英文:
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>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论