oneforall1
oneforall1

Reputation: 35

Data is not displayed from the array on page load

I have made an array which stores the data of the items from my API and tried displaying it in my page.

But the items are not loading on the page.

the array which has the items is this

const allCategory = ["All",...new Set(filteredData.map((curElem)=> {return curElem.Category}))];

In this way I'm displaying the items from the array:


 const [catItems, setCatItems] = useState(allCategory);


    const filterItem = (category) =>{

        if(category === "All"){
            setData(mainArray);
            return;
        }

        const updatedItems = mainArray.filter((curElem)=>{
            return curElem.Category === category;
        })
        setData(updatedItems);
    }
<div>
{
 catItems.map((curClem, index)=>{
    return <li key={index} onClick={() => filterItem(curClem)}>{curClem}</li>
                        })
                    }
</div>

When I tried loading the array in use effect and the complete page goes blank :

useEffect(() => {
        async function fetchData(){
          try {
            const response = await fetch('https://63b6952d1907f863aafa9342.mockapi.io/menu/')
            const data = await response.json();
            setData(data);
            setMainArray(data);
            setCatItems(data);
          } catch (error) {
            console.error(error);
          }
        }
    
        fetchData();
      }, []);

I think I'm making a mistake while loading the array in use effect.

Tell me what is the issue I'm facing or the error I made in my code and help me with solving it.

My data from array is not displayed on page and I tried calling them in use Effect but it is not working. I think I'm making a mistake in calling the set state in use Effect.

I'm providing the sandbox link for further details in my code:

https://codesandbox.io/s/qr-menu-smvr6h?file=/src/App.js

Upvotes: 2

Views: 98

Answers (1)

Drew Reese
Drew Reese

Reputation: 202608

allCategories is what is considered derived state. It's derived from the current data state and the vegOnly state. The data state is fetched on the initial render and updated after the initial render, so it can't be used to compute the initial catItems state.

Derived state doesn't belong in React state, since it's easily derived from other existing state/props/etc. This means the UI should directly reference the computed allCategory array.

...

const [data, setData] = useState([]);
const [vegOnly, setVegOnly] = useState(false);

useEffect(() => {
  async function fetchData() {
    try {
      const response = await fetch(
        "https://63b6952d1907f863aafa9342.mockapi.io/menu/"
      );
      const data = await response.json();
      setData(data);
      setMainArray(data);
    } catch (error) {
      console.error(error);
    }
  }

  fetchData();
}, []);

...

const filteredData =
  vegOnly === false ? data : data.filter((item) => item.Type === "veg"); 
  //from above to here for filter veg only

const allCategory = [
  "All",
  ...new Set(filteredData.map((curElem) => curElem.Category))
]; // 3rd step to make it array

...

<ul>
  {allCategory.map((curClem, index) => {
    return (
      <li key={index} onClick={() => filterItem(curClem)}>
        {curClem}
      </li>
    );
  })}
</ul>

There's a fair amount of redundant/unnecessary state. All the "filtered data" also considered derived state. You should store once copy of the data array in state, and the filtering conditions, not duplicates of the array.

Example:

const App = () => {
  const [data, setData] = useState([]); //solved from stackoverflow
  const [search, setSearch] = useState("");
  const [category, setCategory] = useState("All");
  const [vegOnly, setVegOnly] = useState(false);

  useEffect(() => {
    async function fetchData() {
      try {
        const response = await fetch(
          "https://63b6952d1907f863aafa9342.mockapi.io/menu/"
        );
        const data = await response.json();
        setData(data);
      } catch (error) {
        console.error(error);
      }
    }

    fetchData();
  }, []);

  const handleVegInputChange = (e) => {
    const { checked } = e.target;
    setVegOnly(checked);
  };

  // filter the data inline by the different filtering conditons
  // and selected category.
  const filteredData = data
    .filter((item) => {
      return item.Name.toLowerCase().includes(search.toLowerCase());
    })
    .filter((item) => {
      if (vegOnly) {
        return item.Type === "veg";
      }
      return true;
    })
    .filter((item) => {
      if (category !== "All") {
        return item.Category === category;
      }
      return true;
    });

  // Derive the categories from the data array
  const allCategory = [
    "All",
    ...new Set(data.map((curElem) => curElem.Category))
  ]; // 3rd step to make it array

  // Set the selected filtering category
  const filterItem = (category) => {
    setCategory(category);
  };

  return (
    <div className="first">
      ...
      ...
      <div className="resinfo2">
        <div className="rescategory">
          <ul>
            {allCategory.map((curClem, index) => {
              return (
                <li
                  key={index}
                  // Style the selected category
                  style={{
                    color: curClem === category ? "lightgreen" : "inherit"
                  }}
                  onClick={() => filterItem(curClem)}
                >
                  {curClem}
                </li>
              );
            })}
          </ul>
        </div>

        <div className="resitems">
          <div className="box">
            <input
              type="text"
              className="search-input"
              placeholder="Search for dishes"
              value={search}
              onChange={(e) => setSearch(e.target.value)}
            />
            <img src="/images/search.png" />
          </div>

          <div className="contents">
            {data ? (
              <div>
                <div className="checkbox">
                  <label>
                    <input
                      type="checkbox"
                      value={vegOnly}
                      onChange={handleVegInputChange}
                    />
                    Veg Only
                  </label>
                </div>
                <div className="items">
                  {filteredData.map((item) => (
                    <div className="itemslist" key={item.id}>
                      <ul>
                        <li
                          className={
                            item.Type === "veg" ? "veg" : "non-veg"
                          }
                        ></li>
                        <li>{item.Name}</li>
                        <li>₹ {item.Price}</li>
                        <img src="/images/pizza1.jpg" />
                        <div className="hr"></div>
                      </ul>
                    </div>
                  ))}
                </div>
              </div>
            ) : (
              <div className="loading">Loading...</div>
            )}
          </div>
        </div>
        <div className="rescart"></div>
      </div>
    </div>
  );
};

Edit data-is-not-displayed-from-the-array-on-page-load

Upvotes: 1

Related Questions