javascriptreactjsfiltercheckbox

Filter with multiple checkboxs and fetching data with ReactJS


I'm trying to implement a filter with checkboxes. I have my data in a JSON file. I'm fetching my data from a JSON It looks like:

{
  "subjects": [
    {
      "año_cuatri": "1° 1°",
      "codigo": "1.1.1",
      "nombre": "Técnicas de Programación",
      "estado": "Promocionada",
      "año_cursada": "2024 2°C",
      "nota": 8,
      "tiene_apuntes": true,
      "link_apuntes": "111_tecnicas_de_programacion"
    },
...
]}

I'm trying to render it, and everything is fine up to there, but when I implement filters with checkboxes, I'm having some troubles. I can't filter the data, and re-render the filtered data. Would you mind helping me? So I've got this:

const Materias_List = () => {
  const [dataApi, setDataApi] = useState([]);

  const [estadoChecked, setEstadoChecked] = useState({
    materia_promocionada: false,
    materia_pendiente: false,
    materia_cursando: false,
    materia_tiene_apuntes: false,
  });

  let api_subjects = [];
  let api_subjects_filtered = [];

  const fetchData = async () => {
    try {
      api_subjects = await degree_in_software_development.subjects;
      setDataApi(api_subjects);
    } catch (e) {
      console.log("Error al consumir API", e);
    } finally {
      console.log("FINALLY api_subjects", api_subjects);
      console.log("FINALLY dataApi", dataApi);
      console.log("Finalizó la carga");
    }
  };

  const handleOnChange = async (e) => {
    console.log("handleOnChange", e); // e: SyntheticBaseEvent {} > target: input#materia_cursando > checked: true||false

    console.log("estadoChecked", estadoChecked);
    setEstadoChecked({ ...estadoChecked, [e.target.name]: e.target.checked });
    console.log("estadoChecked", estadoChecked);
    console.log("e.target.checked", e.target.checked);
    console.log("e.target.value", e.target.value);
    console.log("e.target.name", e.target.name);
  };

  useEffect(() => {
    fetchData();
    console.log("useEffect", api_subjects);
    console.log("useEffect dataApi", dataApi);
  }, []);

  return (
    <>
      <div>
        <p>Filtrar por: </p>
        <input
          type="checkbox"
          id="materia_promocionada"
          name="materia_promocionada"
          value="Promocionada"
          onChange={handleOnChange}
        />
        <label htmlFor="materia_promocionada">Promocionada</label>

        <input
          type="checkbox"
          id="materia_pendiente"
          name="materia_pendiente"
          value="Pendiente"
          onChange={handleOnChange}
        />
        <label htmlFor="materia_pendiente">Pendiente</label>

        <input
          type="checkbox"
          id="materia_cursando"
          name="materia_cursando"
          value="Cursando"
          onChange={handleOnChange}
        />
        <label htmlFor="materia_cursando">Cursando</label>

        <input
          type="checkbox"
          id="materia_tiene_apuntes"
          name="materia_tiene_apuntes"
          value="tiene_apuntes"
          onChange={handleOnChange}
        />
        <label htmlFor="materia_tiene_apuntes">Tiene apuntes</label>
      </div>
      <div id="materias_container">
        <ul id="materias_lista">
          {dataApi.map((subject) => {
            return (
              <li key={subject.codigo}>
                <div className="materias__item">
                  <span className={`estado_${subject.estado.toLowerCase()}`}>
                    {subject.estado}
                  </span>
                  <h4>{subject.nombre}</h4>
                  {!subject.tiene_apuntes ? (
                    <p className="materias__item-detalle">
                      <span>Código: {subject.codigo}</span>
                    </p>
                  ) : subject.tiene_apuntes && subject.link_apuntes ? (
                    <p className="materias__item-detalle">
                      <span>Código: {subject.codigo}</span>
                      <span>
                        <a
                          href={`${basePath}${subject.link_apuntes}`}
                          target="#"
                        >
                          📚 Apuntes
                        </a>
                      </span>
                    </p>
                  ) : null}
                </div>
              </li>
            );
          })}
        </ul>
      </div>
    </>
  );
};

Thanks for your time!


Solution

  • import React, { useEffect, useState } from "react";
    
    const Materias_List = () => {
      const [originalData, setOriginalData] = useState([]);
      const [dataApi, setDataApi] = useState([]);
    
      const [estadoChecked, setEstadoChecked] = useState({
        materia_promocionada: false,
        materia_pendiente: false,
        materia_cursando: false,
        materia_tiene_apuntes: false,
      });
    
      const fetchData = async () => {
        try {
          // Simulated fetch (replace with real fetch if needed)
          const response = await fetch("/path/to/your/degree_in_software_development.json");
          const json = await response.json();
          setOriginalData(json.subjects);
          setDataApi(json.subjects);
        } catch (e) {
          console.error("Error al consumir API", e);
        }
      };
    
      const handleOnChange = (e) => {
        const { name, checked } = e.target;
        setEstadoChecked((prev) => ({
          ...prev,
          [name]: checked,
        }));
      };
    
      useEffect(() => {
        fetchData();
      }, []);
    
      // Apply filters every time estadoChecked changes
      useEffect(() => {
        let filtered = [...originalData];
    
        const filters = [];
    
        if (estadoChecked.materia_promocionada) filters.push("Promocionada");
        if (estadoChecked.materia_pendiente) filters.push("Pendiente");
        if (estadoChecked.materia_cursando) filters.push("Cursando");
    
        // Filter by estado (Promocionada, Pendiente, Cursando)
        if (filters.length > 0) {
          filtered = filtered.filter((s) => filters.includes(s.estado));
        }
    
        // Filter by tiene_apuntes
        if (estadoChecked.materia_tiene_apuntes) {
          filtered = filtered.filter((s) => s.tiene_apuntes);
        }
    
        setDataApi(filtered);
      }, [estadoChecked, originalData]);
    
      return (
        <>
          <div>
            <p>Filtrar por: </p>
            <label>
              <input
                type="checkbox"
                name="materia_promocionada"
                onChange={handleOnChange}
              />
              Promocionada
            </label>
            <label>
              <input
                type="checkbox"
                name="materia_pendiente"
                onChange={handleOnChange}
              />
              Pendiente
            </label>
            <label>
              <input
                type="checkbox"
                name="materia_cursando"
                onChange={handleOnChange}
              />
              Cursando
            </label>
            <label>
              <input
                type="checkbox"
                name="materia_tiene_apuntes"
                onChange={handleOnChange}
              />
              Tiene apuntes
            </label>
          </div>
    
          <div id="materias_container">
            <ul id="materias_lista">
              {dataApi.map((subject) => (
                <li key={subject.codigo}>
                  <div className="materias__item">
                    <span className={`estado_${subject.estado.toLowerCase()}`}>
                      {subject.estado}
                    </span>
                    <h4>{subject.nombre}</h4>
                    <p className="materias__item-detalle">
                      <span>Código: {subject.codigo}</span>
                      {subject.tiene_apuntes && subject.link_apuntes && (
                        <span>
                          <a href={`/${subject.link_apuntes}`} target="_blank">
                            📚 Apuntes
                          </a>
                        </span>
                      )}
                    </p>
                  </div>
                </li>
              ))}
            </ul>
          </div>
        </>
      );
    };
    
    export default Materias_List;