This would be my first time of doing this and I can't seem to find a way around it. I would like to persist check box state in react.js and would like this to be done without my MongoDB database. Here are my codes so far: I am fetching list of subscribers from my MongoDB database like this:
const [allSubscribers, setAllSubscribers] = useState([]);
const response = await axiosPrivate.get(`${BASE_URL}/emailsub/subscribers?page=${pageNumber})
setAllSubscribers(response.data)
This displays 9 subscribers per page. On next page, a new API call is made and another 9 subscribers listed, until the last set of items. That is how I handled the pagination via query.
To create the input checkbox, I had to create another array based on the size of the subscribers fetched from the database.
const [checkedState, setCheckedState] = useState();
const totalPosts = allSubscribers.length // to get the length of the items fetched from database
const fillArray = new Array(totalPosts).fill( false)//created new array and fill it with initial value of `false`
//useEffecct to set the check state whenever the all subscriber state changes
useEffect(()=>{
setCheckedState(fillArray)
}, [allSubscribers])
When the checkbox is clicked it returns the opposite of the value of the matched item. And the subscriber Id is passed into an array which is a state called const [selectedSubscriberId, setSelectedSubscriberId] = useState([]);
const arrayOfSelectedPostId = (subscriberId, indexPosition) =>{
setSelectedSubscriberId(prevArray => [...prevArray, subscriberId]);
const updatedCheckedState = checkedState.map((item, index) =>
index == indexPosition ? !item : item
)
setCheckedState(updatedCheckedState);
}
When unchecked, I removed the matched subscriberId from the selectedSubscriberId
array.
//handle deselecting of a selected postid
const handleChangeState = (subscriberId)=>{
selectedSubscriberId.map((item)=>{
console.log(item === subscriberId)
if(item === subscriberId){
const newArray = selectedSubscriberId.filter((item) => item !==subscriberId)
setSelectedSubscriberId(newArray);
}
})
};
This is the checkbox input:
<input type="checkbox" id={index} checked={checkedState[index]} onChange={()=>{arrayOfSelectedPostId(subscriberId, index); handleChangeState(subscriberId)}}/>
On page load or refresh, I want to check the selectedSubscriberId
array and any subscriber id found there should remain checked. Is there a way I can handle this? I don't mind reworking the code if possible.
I think you overcomplicated your state a bit. You could achieve checkboxes state handling using 1 array that holds only ids (for example) of checked items. And 2 utility functions, 1 to check if item is checked and 1 to actually add or remove items from this array of ids.
Next - you would need 2 useEffects. One useEffect will load checked ids array from localstorage on first component render, and 2nd one will update localstorage when array of ids is updated.
import { useState, useEffect, useCallback } from "react";
const DATA = [
{ id: 1, name: "sub1" },
{ id: 2, name: "sub2" },
{ id: 3, name: "sub3" },
{ id: 4, name: "sub4" },
{ id: 5, name: "sub5" }
];
const CHECKED_SUBSCRIBERS_IDS_KEY = "checked_subscribers_ids";
const ITEMS_PER_PAGE = 2;
export default function App() {
const [allSubscribers, setAllSubscribers] = useState([]);
const [page, setPage] = useState(0);
// initial state for it is "undefined"!
const [checkedSubscribersIds, setCheckedSubscribersIds] = useState();
// initial load of checked items from localstorage
useEffect(() => {
const json = localStorage.getItem(CHECKED_SUBSCRIBERS_IDS_KEY);
setCheckedSubscribersIds(json ? JSON.parse(json) : []);
}, []);
// update localstorage on checked items changed.
useEffect(() => {
// initial load needs to be ignored
if (!checkedSubscribersIds) return;
const json = JSON.stringify(checkedSubscribersIds);
localStorage.setItem(CHECKED_SUBSCRIBERS_IDS_KEY, json);
}, [checkedSubscribersIds]);
// dummy data set and pagination, ignore
useEffect(() => {
const items = [...DATA].slice(
page * ITEMS_PER_PAGE,
page * ITEMS_PER_PAGE + ITEMS_PER_PAGE
);
setAllSubscribers(items);
}, [page]);
const isChecked = useCallback(
(item) => {
if (!checkedSubscribersIds) return false;
return checkedSubscribersIds.includes(item.id);
},
[checkedSubscribersIds]
);
const handleCheckedClick = useCallback(
(item) => {
const idx = checkedSubscribersIds.findIndex((x) => x === item.id);
if (idx >= 0) {
checkedSubscribersIds.splice(idx, 1);
} else {
checkedSubscribersIds.push(item.id);
}
setCheckedSubscribersIds([...checkedSubscribersIds]);
},
[checkedSubscribersIds]
);
// ignore
const onPrevPageClick = () => {
setPage(page <= 0 ? 0 : page - 1);
};
// ignore
const onNextPageClick = () => {
setPage(page + 1 >= DATA.length / ITEMS_PER_PAGE ? page : page + 1);
};
return (
<div className="App">
<table>
<thead>
<tr>
<th>Checked</th>
<th>Id</th>
<th>Name</th>
</tr>
</thead>
<tbody>
{allSubscribers.map((x) => (
<tr key={x.id}>
<td>
<input
type="checkbox"
checked={isChecked(x)}
onChange={() => handleCheckedClick(x)}
/>
</td>
<td>{x.id}</td>
<td>{x.name}</td>
</tr>
))}
</tbody>
</table>
<button type="button" onClick={onPrevPageClick}>
Previous
</button>
<button type="button" onClick={onNextPageClick}>
Next
</button>
</div>
);
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.