Home > Mobile >  How to fix the array state filtering data in react hooks
How to fix the array state filtering data in react hooks

Time:11-11

import { useState } from "react";

function App() {
  const [itemsClicked, setItemsClicked] = useState([]);
  const dataList = [
    { id: 1, name: "jake" },
    { id: 12, name: "edd" },
    { id: 13, name: "john" }
  ];

  const highlight = (data) => {
    setItemsClicked((array) => {
      let itemClicked = array.includes(data)
        ? array.filter((x, i) => x.id !== data.id)
        : [...array, data]; // What I'm trying to do here is to add a new field which is 'active' >> [...array, {...data, active: true}];

      return itemClicked;
    });
  };

  return (
    <div>
      {dataList.map((item, i) => (
        <div
          style={{
            borderColor: itemsClicked[i]?.active ? "1px solid green" : ""
          }}
        >
          <button onClick={() => highlight(dataList[i])}>HIGHLIGHT</button>
        </div>
      ))}
    </div>
  );
}

export default App;

What I'm trying to do here is to create a toggle which is to highlight the div. but my problem is on the state instead of it will remove the data object, it will continue appending. how to fix it?

for example when I try to click the first data which is jake, the output should be like this in itemsClicke

[{ id: 1, name: jake, active: true }]

but when I try to click again it will just remove it from the list, but on my side, it continuing to append the data which is wrong

[{ id: 1, name: jake, active: true },{ id: 1, name: jake, active: true },{ id: 1, name: jake, active: true },{ id: 1, name: jake, active: true }]

CodePudding user response:

Just use this. It's a simple example. I used itemsClicked only for storing the ids

const highlight = (data) => { 
      if(itemsClicked.indexOf(data.id) == -1)
      {
        setItemsClicked(prevData => { 
          return [...prevData, data.id]
        })
      }  
    }

 {
  dataList.map((item, i) => (
    <div
      style={{
        border:
          itemsClicked.indexOf(item.id) > -1 ? '1px solid green' : '',
      }}
    >
      {itemsClicked.indexOf(item.id) > -1 ? '1px solid green' : ''}
      <button onClick={() => highlight(dataList[i])}>HIGHLIGHT</button>
    </div>
  ))
  }

CodePudding user response:

You can simply remove the itemsClicked state and put the dataList in a state variable to have control over it:

const [dataList, setDataList] = useState([
  { id: 1, name: "jake" },
  { id: 12, name: "edd" },
  { id: 13, name: "john" }
]);

Now, you need to check an isActive property to conditionally add some styles, so you need isActive but it's not in the current dataList and you created itemsClicked to solve this issue. But there are some simpler solutions like adding a property on the fly with your dataList.

You can implement toggleHighlight function to change isActive property:

const toggleHighlight = (id) => {
  setDataList((prevState) =>
    prevState.map((item) =>
      item.id === id ? { ...item, isActive: !item.isActive } : item
    )
  );
};

this toggleHandler will accept an id and take a for loop over the dataList, it finds the clicked item. if it's an active item so it changes it to false and vice versa.

let's recap and put all things together:

import { useState } from "react";

function App() {
  const [dataList, setDataList] = useState([
    { id: 1, name: "jake" },
    { id: 12, name: "edd" },
    { id: 13, name: "john" }
  ]);

  const toggleHighlight = (id) => {
    setDataList((prevState) =>
      prevState.map((item) =>
        item.id === id ? { ...item, isActive: !item.isActive } : item
      )
    );
  };

  return (
    <div>
      {dataList.map((item) => (
        <div
          key={item.id}
          style={{
            display: "flex",
            paddingTop: 10,
            border: item.isActive ? "2px solid green" : ""
          }}
        >
          <p style={{ padding: 5 }}>{item.name}</p>
          <button onClick={() => toggleHighlight(item.id)}>HIGHLIGHT</button>
        </div>
      ))}
    </div>
  );
}

export default App;

Try this on a live playground Edit add unique key for each child

CodePudding user response:

array.includes(data)

won't return true because of this: https://stackoverflow.com/a/50371323/17357155

  • Related