Home > Software engineering >  Table values does not change in react
Table values does not change in react

Time:12-24

Im fetching data from an API and changing the value from the frontend to display it in a table. Im fetching a list of objects and storing it in a state and displaying the objects in the state in a html table. The table has a checkbox to display a boolean value. If the value is true, then defaultChecked is true in the checkbox. There's a checkbox in the table header to check or uncheck all items.

The following is the json object which i fetch.

{
completed: false
id: 1
title: "delectus aut autem"
userId: 1
}

If I checked the checkbox in the table header, I want to set completed to true in all 200 items.

The following is the code to set all items to either true or false.

const checkAllHandler = (e) => {
    let val = e.target.checked;
    console.log(val);
    let allTodoList = [];

    if (val === true) {
      if (todo.length > 0) {
        
        for (let index = 0; index < todo.length; index  ) {
          const newObject = {
            userId: todo[index].userId,
            id: todo[index].id,
            title: todo[index].title,
            completed: true,
          };
          allTodoList.push(newObject);
        }
        setTodo(allTodoList);
        
      }
    } else if (val === false) {
      if (todo.length > 0) {
       
        for (let index = 0; index < todo.length; index  ) {
          const newObject = {
            userId: todo[index].userId,
            id: todo[index].id,
            title: todo[index].title,
            completed: false,
          };
          allTodoList.push(newObject);
        }
        setTodo(allTodoList);
        
      }
    }
  };

When I console the todo state, all the values are updated to either true or false but it doesnt show on the table. The table has a filter function. If I filter a word and go back, then the values of entire table is changing. I want to display the change when the checkbox is clicked and not when search and go back. How to I do that?

The complete code of the component is below.

const DataTable = () => {
  const { loading, items } = useSelector((state) => state.allData);
  // console.log(items)

  const dispatch = useDispatch();
  // const history = useNavigate();

  const [searchText, setsearchText] = useState("");
  const [todo, setTodo] = useState(items);
  console.log("todo");
  console.log(todo);
  const [isFetch, setisFetch] = useState(false);
  const [checkedloading, setcheckedLoading] = useState(false);
  const [isChecked, setisChecked] = useState(false);
  console.log(isChecked);

  useEffect(() => {
    const setDataToState = () => {
      if (loading === false) {
        setTodo(items);
      }
    };
    setDataToState();
  }, [loading]);

  useEffect(() => {
    
    dispatch(getData());
    // setTodo(items)
    // console.log(items)
  }, [dispatch]);
  //etTodo(items)
  const handleSearch = (event) => {
    //let value = event.target.value.toLowerCase();
    setsearchText(event.target.value);
  };

  const onChangeHandler = (e, item) => {
    console.log(e.target.checked);
    console.log(item);

    if (e.target.checked === true) {
      // const item = todo.filter(x=> x.id === id)
      // console.log("added")
      // console.log(item)

      for (let index = 0; index < todo.length; index  ) {
        if (todo[index].id === item.id) {
          console.log(todo[index]);
          console.log("deleting");
          todo.splice(index, 1);
          console.log("deleted");
          const newObject = {
            userId: item.userId,
            id: item.id,
            title: item.title,
            completed: true,
          };
          console.log("adding updated object");
          todo.splice(index, 0, newObject);
          console.log("added");

          console.log(todo);
        }
      }
    } else {
      // const item = todo.filter(x=> x.id === id)
      // console.log("removed")
      // console.log(item)
      for (let index = 0; index < todo.length; index  ) {
        if (todo[index].id === item.id) {
          console.log(todo[index]);
          console.log("deleting");
          todo.splice(index, 1);
          console.log("deleted");
          const newObject = {
            userId: item.userId,
            id: item.id,
            title: item.title,
            completed: false,
          };
          console.log("adding updated object");
          todo.splice(index, 0, newObject);
          console.log("added");

          console.log(todo);
        }
      }
    }
  };

  const onSubmitHandler = () => {
    localStorage.setItem("items", JSON.stringify(todo));
  };
  const getItem = () => {
    const items = localStorage.getItem("items");
    console.log("local storage items");
    console.log(JSON.parse(items));
  };

  const checkAllHandler = async (e) => {
    const { checked } = e.target;
    console.log(checked);
    setTodo((todos) =>
      todos.map((todo) => ({
        ...todo,
        completed: checked,
      }))
    );
   
  };

  return (
    <>
      {console.log("todo in render")}
      {console.log(todo)}
      <div className={styles.container}>
        <div className={styles.top}>
          <div className={styles.search_bar}>
            <input
              type="text"
              onChange={(e) => handleSearch(e)}
              placeholder="search by name"
            />
          </div>
        </div>

        <div className={styles.btn_container}>
          <button onClick={onSubmitHandler}>Submit</button>
        </div>

        <div className={styles.data_table_container}>
          {checkedloading === false ? (
            <>
              <div className={styles.data_table}>
                {loading || todo === null || todo === undefined ? (
                  <>
                    <p>Loading!!</p>
                  </>
                ) : (
                  <>
                    <table>
                      <tr>
                        <th>ID</th>
                        <th>userId</th>
                        <th>Title</th>
                        <th>
                          <>
                            Completed
                            <input type="checkbox" onChange={checkAllHandler} />
                          </>
                        </th>
                      </tr>
                      <tbody>
                        {todo
                          .filter((val) => {
                            if (searchText === "") {
                              return val;
                            } else if (
                              val.title.toLowerCase().includes(searchText)
                            ) {
                              return val;
                            }
                          })
                          .map((item) => (
                            <>
                              <tr key={item.id}>
                                <td>{item.id}</td>
                                <td>{item.userId}</td>
                                <td>{item.title}</td>
                                <td>
                                  <input
                                    type="checkbox"
                                    defaultChecked={item.completed}
                                    onClick={(e) => onChangeHandler(e, item)}
                                  />
                               
                                </td>
                               
                              </tr>
                            </>
                          ))}
                      </tbody>
                    </table>
                  </>
                )}
              </div>
            </>
          ) : (
            <>Loading</>
          )}
        </div>
      </div>
    </>
  );
};

CodeSandbox link: Edit dazzling-sunset-t5z80

Update #2

The individual checkbox inputs were being mutated with Array.prototype.splice in onChangeHandler. .splice does an in-place mutation. Again a functional state update should be used to shallow copy the previous state and check for the matched todo object by id.

const onChangeHandler = (e, item) => {
  const { checked } = e.target;

  setTodo((todos) =>
    todos.map((todo) =>
      todo.id === item.id
        ? {
            ...todo,
            completed: checked
          }
        : todo
    )
  );
};
  • Related