问题
I am making a react application where checkboxes for jobtitles are populated from the dynamic data from api and it will be exactly like given snippet.
const departments =
[
{
"sectorId":29,
"sectorName":"Building Materials Mfg. & Distribution",
"departments":[
{
"deptName":"Manufacturing",
"jobTitles":[
{
"453":false,
"JobTitleID":453,
"DepartmentID":101,
"JobName":"Consultant",
"Deleted":false,
"SortOrder":5
},
{
"323":true,
"JobTitleID":323,
"DepartmentID":101,
"JobName":"Quality Control",
"Deleted":false,
"SortOrder":1
}
]
},
{
"deptName":"Warehouse",
"jobTitles":[
{
"326":false,
"JobTitleID":326,
"DepartmentID":98,
"JobName":"Warehouse Supervisor",
"Deleted":false,
"SortOrder":1
}
]
},
{
"deptName":"Administration",
"jobTitles":[
{
"384":true,
"JobTitleID":384,
"DepartmentID":115,
"JobName":"Controller",
"Deleted":false,
"SortOrder":1
}
]
}
]
}
]
const handleJobTitle = (event, job) => {
const { checked } = event.target;
if (checked) {
document.getElementById(job.JobTitleID).checked = true;
} else {
document.getElementById(job.JobTitleID).checked = false;
}
console.log(document.getElementById(job.JobTitleID));
};
const App = () => (
<div> {departments && departments.map((levelOne, i) => (
<div
key={i}
>
<p> {levelOne.sectorName} </p>
{levelOne.departments.map((levelTwo, j) => (
<div key={j}>
<p >
{" "}
{levelTwo.deptName}{" "}
</p>
{levelTwo.jobTitles.map((job, l) => (
<div
key={l}
>
<input type="checkbox" id={job.JobTitleID} onChange={(e) => {handleJobTitle(e, job)}} name={job.JobName} checked={job[job.JobTitleID]}/>
<span>{job.JobName}</span>
</div>
))}
</div>
))}
</div>
))} </div>
)
// Render it
ReactDOM.render(
<App />,
document.getElementById("root")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Here the jobTitles data will be like,
"jobTitles":[
{
"453":false,
"JobTitleID":453,
"DepartmentID":101,
"JobName":"Consultant",
"Deleted":false,
"SortOrder":5
},
{
"323":true,
"JobTitleID":323,
"DepartmentID":101,
"JobName":"Quality Control",
"Deleted":false,
"SortOrder":1
}
]
And I make the checkbox checked based on the value of "453":false like,
<input type="checkbox" ...... checked={job[job.JobTitleID]}/>
And the checkboxes are checked here but when I try to uncheck the checkbox in onChange handler like,
const handleJobTitle = (event, job) => {
document.getElementById(job.JobTitleID).checked = false;
}
The checkboxes are not unchecked.. If I console/inspect the input element then the checked atribute is not removed.
Additional Info: It is also not possible to check the checkbox which is in unchecked state.. So in common I couldn't make any change to checkbox..
Could anybody please help me to achieve the solution and I am got stuck for too long with this as I am new to react..
Big thanks in advance.
回答1:
Issue(s)
Direct DOM mutation is an anti-pattern in react (it is outside react so react can't know to rerender).
The handler also doesn't access the checked property of the onChange event.
const { checked } = event; // <-- should be event.target
Solution
Use react state to maintain the checked status in component state.
Move the departments data into component state.
const [departments, setDepartments] = useState(departmentsData);
Move the handleJobTitle handler into the component. I suggest using a curried function that accepts the sector id, department name, and the job id, you'll need these to "trace" the path to the correct nested object. You don't need to worry about getting the checked property from event.target as you can simply invert a checked value in state via the JobTitleID key value.
The idea here is to shallow copy any nested state, into new object references for react, that is being updated.
const handleJobTitle = (sectorId, deptName, JobTitleID) => () => {
setDepartments((data) =>
data.map((sector) =>
sector.sectorId === sectorId
? {
...sector,
departments: sector.departments.map((dept) =>
dept.deptName === deptName
? {
...dept,
jobTitles: dept.jobTitles.map((job) =>
job.JobTitleID === JobTitleID
? {
...job,
[JobTitleID]: !job[JobTitleID]
}
: job
)
}
: dept
)
}
: sector
)
);
};
Now simply attach the handleJobTitle to the input's onChange handler.
<input
type="checkbox"
id={job.JobTitleID}
onChange={handleJobTitle( // <-- pass the required values
levelOne.sectorId,
levelTwo.deptName,
job.JobTitleID
)}
name={job.JobName}
checked={job[job.JobTitleID]}
/>
回答2:
You need to define an Id parameter in the input tag.
<input type="checkbox" id="JobTitleCheckBox" ...... checked={job[job.JobTitleID]}/>
Then use that id to fetch the node and change its status
const handleJobTitle = (event, job) => {
document.getElementById(job.JobTitleID).checked = false;
}
来源:https://stackoverflow.com/questions/64604518/unable-to-check-uncheck-the-checkbox