我在 React 應用程式中創建了一個條形圖。此圖表是動態的,通過選中每個復選框,需要上傳一組資料。
問題:資料正在更新并顯示在圖表上,但是當我單擊該特定復選框時,沒有任何反應并且圖表無法恢復到原始狀態。我嘗試切換復選框的狀態,但問題仍然存在且圖表未更新。
這是我的代碼:
import React, { useEffect, useState } from "react";
import { Bar } from "react-chartjs-2";
const RandomStatic = (props) => {
let jsonData = [
{ gender: "female" },
{ gender: "male" },
{ gender: "female" },
{ gender: "male" },
{ gender: "female" },
{ gender: "male" },
{ gender: "female" },
{ gender: "female" },
{ gender: "female" },
{ gender: "female" },
];
const [userFemaleCounter, setUserFemaleCounter] = useState();
const [userMaleCounter, setUserMaleCounter] = useState();
const [totalCounter, setTotalCounter] = useState();
const [femalePercentage, setFemalePercentage] = useState();
const [malePercentage, setMalePercentage] = useState();
const [chartData, setChartData] = useState(jsonData);
const [femaleIsChecked, setFemaleIsChecked] = useState(false);
const [maleIsChecked, setMaleIsChecked] = useState(false);
useEffect(() => {
// Getting all Data in an array
let allData = jsonData.map(function (e) {
return e.gender;
});
console.log(allData);
// Display Gender data on the chart
let fCounter = [];
let mCounter = [];
allData.forEach((gender) => {
if (gender === "female") {
fCounter = fCounter;
} else if (gender === "male") {
mCounter = mCounter;
}
});
let userFemaleCounter = fCounter;
setUserFemaleCounter(fCounter);
console.log(userFemaleCounter);
let userMaleCounter = mCounter;
setUserMaleCounter(mCounter);
console.log(userMaleCounter);
let totalCounter = fCounter mCounter;
setTotalCounter(totalCounter);
console.log(totalCounter);
let femalePercentage = (fCounter / totalCounter) * 100;
setFemalePercentage(femalePercentage);
let malePercentage = (mCounter / totalCounter) * 100;
setMalePercentage(malePercentage);
}, [chartData]);
useEffect(() => {
///change the jsonData
//setChartData
let allData = chartData.map(function (e) {
return e.gender;
});
let mCounter = [];
let fCounter = [];
allData.forEach((gender) => {
if (gender === "female") {
fCounter = fCounter;
} else if (gender === "male") {
mCounter = mCounter;
}
});
let totalCounter = fCounter mCounter;
setTotalCounter(totalCounter);
let userFemaleCounter = fCounter;
setUserFemaleCounter(userFemaleCounter);
let femalePercentage = (fCounter / totalCounter) * 100;
setFemalePercentage(femalePercentage);
let userMaleCounter = 0;
setUserMaleCounter(userMaleCounter);
let malePercentage = 0;
setMalePercentage(malePercentage);
}, [femaleIsChecked]);
//useeffect for MALE checkbox
useEffect(() => {
let allData = jsonData.map(function (e) {
return e.gender;
});
let mCounter = [];
let fCounter = [];
allData.forEach((gender) => {
if (gender === "female") {
fCounter = fCounter;
} else if (gender === "male") {
mCounter = mCounter;
}
});
let totalCounter = fCounter mCounter;
setTotalCounter(totalCounter);
let malePercentage = (mCounter / totalCounter) * 100;
setMalePercentage(malePercentage);
fCounter = [];
let femalePercentage = [];
setFemalePercentage(femalePercentage);
}, [maleIsChecked]);
const toggleFemale = () => {
if(femaleIsChecked == true)
{
setFemaleIsChecked(false)
}else{
setFemaleIsChecked(true)
}
}
const toggleMale = () => setMaleIsChecked(chartData)
const toggleAll = () => setChartData(!chartData)
//console.log(toggleFemale)
return (
<div>
<Bar
className="chart"
data={{
labels: ["Female", "Male"],
datasets: [
{
data: [femalePercentage, malePercentage],
backgroundColor: ["green", "yellow"],
borderColor: ["green", "yellow"],
borderWidth: 0.5,
},
],
}}
options={{
responsive: true,
maintainAspectRatio: false,
plugins: {
title: {
display: true,
text: "Male and Female Ratio",
},
legend: {
display: false,
},
},
scales: {
y: {
display: true,
title: {
display: true,
text: "Percentage",
},
},
x: {
display: true,
title: {
display: true,
text: "Population",
},
},
},
showTooltips: false,
hover: false,
}}
/>
<div className="checkbox-form-wrapper">
<div className="chartBox">
<label>Female Only</label>
<input
name="femalePercentage"
type="checkbox"
//checked={femaleIsChecked}
onChange={toggleFemale}
/>
<label>Male Only</label>
<input
name="malePercentage"
type="checkbox"
checked={maleIsChecked}
onChange={toggleMale}
/>
<label>Both Female and Male</label>
<input
name="chartData"
type="checkbox"
checked={chartData}
onChange={toggleAll}
/>
</div>
</div>
</div>
);
};
export default RandomStatic;
謝謝 :)
uj5u.com熱心網友回復:
為了使上面的代碼按預期作業,需要進行的主要更改是:
在每個 Effect 中添加警衛以僅在該標志為真時運行。maleIsChecked 的示例:
if(!maleIsChecked) { 回傳; }
對于顯示 both的Effect,請確保它僅在兩個標志都關閉時運行:
if(femaleIsChecked ||maleIsChecked) { return;}
并且它在每次更改時運行
useEffect(() => { ... }, [chartData,maleIsChecked,femaleIsChecked]):
更新切換功能以“正確”切換。toggleMale 示例:
const toggleMale = () => setMaleIsChecked(!maleIsChecked)
但是,我強烈建議將方法從復選框切換到單選按鈕。對我來說,這似乎比互動更自然,因為您擁有“桌面上”的所有選項,而且它們是相互排斥的。下面建議的作業代碼,用 CHANGE 突出顯示的更改:
import React, { useEffect, useState } from "react";
import { Bar } from "react-chartjs-2";
// CHANGE: define an enum to handle data types to be displayed
const TypesOfDataToDisplay = {
MALE: 'male',
FEMALE: 'female',
BOTH: 'both'
}
const RandomStatic = (props) => {
let jsonData = [
{ gender: "female" },
{ gender: "male" },
{ gender: "female" },
{ gender: "male" },
{ gender: "female" },
{ gender: "male" },
{ gender: "female" },
{ gender: "female" },
{ gender: "female" },
{ gender: "female" },
];
const [userFemaleCounter, setUserFemaleCounter] = useState();
const [userMaleCounter, setUserMaleCounter] = useState();
const [totalCounter, setTotalCounter] = useState();
const [femalePercentage, setFemalePercentage] = useState();
const [malePercentage, setMalePercentage] = useState();
const [chartData, setChartData] = useState(jsonData);
// CHANGE: define a new state that indicates data type to be displayed
const [dataToDisplay, setDataToDisplay] = useState(TypesOfDataToDisplay.BOTH);
// CHANGE: remove boolean states (using them, for each toggle you will generate two renderings)
//const [femaleIsChecked, setFemaleIsChecked] = useState(false);
//const [maleIsChecked, setMaleIsChecked] = useState(false);
useEffect(() => {
// CHANGE: skip this effect if not needed
if(dataToDisplay !== TypesOfDataToDisplay.BOTH) {
return;
}
// Getting all Data in an array
let allData = jsonData.map(function (e) {
return e.gender;
});
console.log(allData);
// Display Gender data on the chart
let fCounter = [];
let mCounter = [];
allData.forEach((gender) => {
if (gender === "female") {
fCounter = fCounter;
} else if (gender === "male") {
mCounter = mCounter;
}
});
let userFemaleCounter = fCounter;
setUserFemaleCounter(fCounter);
console.log(userFemaleCounter);
let userMaleCounter = mCounter;
setUserMaleCounter(mCounter);
console.log(userMaleCounter);
let totalCounter = fCounter mCounter;
setTotalCounter(totalCounter);
console.log(totalCounter);
let femalePercentage = (fCounter / totalCounter) * 100;
setFemalePercentage(femalePercentage);
let malePercentage = (mCounter / totalCounter) * 100;
setMalePercentage(malePercentage);
}, [chartData, dataToDisplay]); // CHANGE: make sure the effect is called on data type change
useEffect(() => {
// CHANGE: skip this effect if not needed
if(dataToDisplay !== TypesOfDataToDisplay.FEMALE) {
return;
}
///change the jsonData
//setChartData
let allData = chartData.map(function (e) {
return e.gender;
});
let mCounter = [];
let fCounter = [];
allData.forEach((gender) => {
if (gender === "female") {
fCounter = fCounter;
} else if (gender === "male") {
mCounter = mCounter;
}
});
let totalCounter = fCounter mCounter;
setTotalCounter(totalCounter);
let userFemaleCounter = fCounter;
setUserFemaleCounter(userFemaleCounter);
let femalePercentage = (fCounter / totalCounter) * 100;
setFemalePercentage(femalePercentage);
let userMaleCounter = 0;
setUserMaleCounter(userMaleCounter);
let malePercentage = 0;
setMalePercentage(malePercentage);
}, [dataToDisplay]); // CHANGE: make sure the effect is called on data type change
//useeffect for MALE checkbox
useEffect(() => {
// CHANGE: skip this effect if not needed
if(dataToDisplay !== TypesOfDataToDisplay.MALE) {
return;
}
let allData = jsonData.map(function (e) {
return e.gender;
});
let mCounter = [];
let fCounter = [];
allData.forEach((gender) => {
if (gender === "female") {
fCounter = fCounter;
} else if (gender === "male") {
mCounter = mCounter;
}
});
let totalCounter = fCounter mCounter;
setTotalCounter(totalCounter);
let malePercentage = (mCounter / totalCounter) * 100;
setMalePercentage(malePercentage);
fCounter = [];
let femalePercentage = [];
setFemalePercentage(femalePercentage);
}, [dataToDisplay]); // CHANGE: make sure the effect is called on data type change
// CHANGE: remove togglers for the boolean states
/*const toggleFemale = () => {
if(femaleIsChecked == true)
{
setFemaleIsChecked(false)
}else{
setFemaleIsChecked(true)
}
}
const toggleMale = () => setMaleIsChecked(chartData)
const toggleAll = () => setChartData(!chartData)*/
// CHANGE: add only one handler for changing data to be displayed
const toggleDisplay = (event) => {
setDataToDisplay(event.currentTarget.value);
}
// CHANGE: switch from checkboxes to radio buttons and update definitions with new handler
return (
<div className="chartContainer">
<Bar
className="chart"
data={{
labels: ["Female", "Male"],
datasets: [
{
data: [femalePercentage, malePercentage],
backgroundColor: ["green", "yellow"],
borderColor: ["green", "yellow"],
borderWidth: 0.5,
},
],
}}
options={{
responsive: true,
maintainAspectRatio: false,
plugins: {
title: {
display: true,
text: "Male and Female Ratio",
},
legend: {
display: false,
},
},
scales: {
y: {
display: true,
title: {
display: true,
text: "Percentage",
},
},
x: {
display: true,
title: {
display: true,
text: "Population",
},
},
},
showTooltips: false,
hover: false,
}}
/>
<div className="checkbox-form-wrapper">
<div className="chartBox">
<label>Female Only</label>
<input
name="femalePercentage"
type="radio"
value={TypesOfDataToDisplay.FEMALE}
checked={dataToDisplay === TypesOfDataToDisplay.FEMALE}
onChange={toggleDisplay}
/>
<label>Male Only</label>
<input
name="malePercentage"
type="radio"
value={TypesOfDataToDisplay.MALE}
checked={dataToDisplay === TypesOfDataToDisplay.MALE}
onChange={toggleDisplay}
/>
<label>Both Female and Male</label>
<input
name="chartData"
type="radio"
value={TypesOfDataToDisplay.BOTH}
checked={dataToDisplay === TypesOfDataToDisplay.BOTH}
onChange={toggleDisplay}
/>
</div>
</div>
</div>
);
};
export default RandomStatic;
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/362498.html
標籤:javascript 反应 接口 反应钩子 获取-api
