skip to Main Content

I am having a problem with my state managment.

When I click on the select box, nothing happens, when I click on it a 2nd time, it is like it accepts the first click.

This should be showing all the People rows, but it is showing the onChange from before.
enter image description here

Also bonus point if the double useEffects can be modified to be only one function 🙂

import { React, useEffect, useState } from "react";
import TableRow from "../../components/TableRow/TableRow";
import axios from "axios";
export default function SellerList() {
  const [rowData, setRowData] = useState({});
  const [categoryValue, setCategoryValue] = useState();
  const [sdlrValue, setSdlrValue] = useState();

  useEffect(() => {
    axios
      .get("SellerList.json")
      .then(function (response) {
        setRowData(response["data"]);
      })
      .catch(function (error) {
        console.log(error);
      });
  }, []);

  useEffect(() => {
    Object.keys(rowData).map((rowKey, i) => {
      rowData[rowKey] = { ...rowData[rowKey], isHidden: false };
      return 1;
    });
    if (categoryValue !== "00") {
      Object.keys(rowData).map((rowKey, i) => {
        if (categoryValue !== rowData[rowKey]["code"]) {
          rowData[rowKey] = { ...rowData[rowKey], isHidden: true };
        }
        return 1;
      });
    }
  }, [rowData, categoryValue]);

  useEffect(() => {
    Object.keys(rowData).map((rowKey, i) => {
      rowData[rowKey] = { ...rowData[rowKey], isHidden: false };
      return 1;
    });
    if (sdlrValue !== "00") {
      Object.keys(rowData).map((rowKey, i) => {
        if (sdlrValue !== rowData[rowKey]["sdlrId"]) {
          rowData[rowKey] = { ...rowData[rowKey], isHidden: true };
        }
        return 1;
      });
    }
  }, [rowData, sdlrValue]);

  return (
    <div>
      <h1>Seller Deduplicated Request List</h1>
      <table>
        <thead>
          <tr>
            <th></th>
            <th>Code</th>
            <th>Category</th>
            <th>SDRL ID</th>
            <th>Data Requested (Name or Label for request)</th>
            <th>Request Parameters (Date ranges, etc)</th>
            <th>Request Details (Notes to explain request)</th>
            <th>Format (File type or format for request)</th>
          </tr>
          <tr>
            <th></th>
            <th colSpan={2}>
              <select
                value={categoryValue}
                onChange={(event) => setCategoryValue(event.target.value)}
              >
                <option value="00">Filter by Category</option>
                <option value="02">People</option>
                <option value="01">Finance & Accounting</option>
                <option value="04">Purchasing</option>
                <option value="01">Sales</option>
              </select>
            </th>
            <th>
              <select
                value={sdlrValue}
                onChange={(event) => setSdlrValue(event.target.value)}
              >
                <option value="00">Filter by SDLR</option>
                <option value="01.02">01.02</option>
                <option value="02.01">02.01</option>
                <option value=" 04.01"> 04.01</option>
                <option value="05.01">05.01</option>
              </select>
            </th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
            <th></th>
          </tr>
        </thead>
        <tbody>
          {rowData &&
            Object.keys(rowData).map((rowKey, i) => {
              return (
                <TableRow
                  key={rowKey}
                  row={rowData[rowKey]}
                  setRowData={setRowData}
                  rowData={rowData}
                />
              );
            })}
        </tbody>
      </table>
    </div>
  );
}

2

Answers


  1. Your code:

    rowData[rowKey] = { ...rowData[rowKey], isHidden: false };
    

    is modifying a state variable value without using the "set state function". So React is not aware that the value has changed (to React, modifying the state variable value directly is just changing any other standard variable). So React doesn’t re-render until something else in state changes…at which point the changes you made earlier are finally reflected.

    It is a REALLY BAD IDEA to change values of a state variable directly. You almost certainly want to be using the "set state function" to change the value, which queues the component to be re-rendered.

    Remember that React only re-renders a component in 2 cases:

    1. the component’s parent renders (which causes it to render all its children)
    2. a state variable in the component is given a new value by use of the "set state function"

    Also, it doesn’t make sense to use the .map() function if you aren’t going to use its return value. Use .forEach() instead.

    Though in this case, it might be a good idea to use the .map() and give its return value to the "set state function" as the new state variable value!

    setRowData(currVal =>  Object.keys(currVal).map((rowKey, i) => {
          rowData[rowKey] = { ...rowData[rowKey], isHidden: false };
          return 1;
        }));
    

    I just gave a decent (IMO) overview of the difference in the two "set state function" signatures that would be useful here too:

    Login or Signup to reply.
  2. You can use the functional form of setRowData that allows you to access the previous state and ensure that you are working with the most up-to-date data. Additionally, you can combine the two useEffect hooks into a single one to reduce redundancy.

      useEffect(() => {
        setRowData(prevData => {
          const updatedData = { ...prevData };
    
          Object.keys(updatedData).forEach(rowKey => {
            updatedData[rowKey] = { ...updatedData[rowKey], isHidden: false };
            if (categoryValue && categoryValue !== "00" && categoryValue !== updatedData[rowKey]["code"]) {
              updatedData[rowKey] = { ...updatedData[rowKey], isHidden: true };
            }
            if (sdlrValue && sdlrValue !== "00" && sdlrValue !== updatedData[rowKey]["sdlrId"]) {
              updatedData[rowKey] = { ...updatedData[rowKey], isHidden: true };
            }
          });
    
          return updatedData;
        });
      }, [categoryValue, sdlrValue]);
    
      return (
        <div>
          <h1>Seller Deduplicated Request List</h1>
          <table>
            {/* ... (your table header) */}
            <tbody>
              {Object.keys(rowData).map((rowKey, i) => (
                <TableRow key={i} rowData={rowData[rowKey]} />
              ))}
            </tbody>
          </table>
        </div>
      );
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search