简体   繁体   中英

Can't persist checkstate in reactjs and nodejs

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM