1

When I change the data file where I have stored my array of data, component where that data is being displayed doesn't change. I have tried to filter the original data and get only the selected values and it worked well but the display hasn't changed even after the data was changed.

Here are the code of key components and a screenshot enter image description here

Single item component:

function Item() {
  let [data, setData] = useContext(DataContext);

  let Array = data.map((item) => {
    return (
      <div className="Item">
        <img src={item.url} />
        <h1>{item.name}</h1>
        <p>{item.desc}</p>
        <h2>{item.price}</h2>
        <Link to={`/product/${item.path}`}>
          <h3>See details</h3>
        </Link>
      </div>
    );
  });

  return <>{Array}</>;
}

Data component:

export let DataContext = createContext();

export let DataProvider = (props) => {
  let [data, setData] = useState([
    {
      name: "Toshiba",
      desc: "Laptop copmuter",
      price: 299,
      url:
        "https://images.pexels.com/photos/3975677/pexels-photo-3975677.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940",
      path: "Toshiba",
      type: "laptop",
      details:
        "Some words just to fill this space Some words just to fill this space Some words just to fill this space Some words just to fill this space Some words just to fill this space Some words just to fill this space Some words just to fill this space Some words just to fill this space",
    },
    {
      name: "Lenovo",
      desc: "Laptop copmuter",
      price: 399,
      url:
        "https://images.pexels.com/photos/3975677/pexels-photo-3975677.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940",
      path: "Lenovo",
      type: "laptop",
      details:
        "Some words just to fill this space Some words just to fill this space Some words just to fill this space Some words just to fill this spaceSome words just to fill this space Some words just to fill this space Some words just to fill this space Some words just to fill this space",
    },
    {
      name: "Asus",
      desc: "Laptop copmuter",
      price: 199,
      url:
        "https://images.pexels.com/photos/3975677/pexels-photo-3975677.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940",
      path: "Asus",
      type: "laptop",
      details:
        "Some words just to fill this space Some words just to fill this space Some words just to fill this space Some words just to fill this space Some words just to fill this space Some words just to fill this space Some words just to fill this space Some words just to fill this space",
    },
    {
      name: "HP",
      desc: "Laptop copmuter",
      price: 299,
      type: "laptop",
      url:
        "https://images.pexels.com/photos/3975677/pexels-photo-3975677.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940",
      path: "HP",
      details:
        "Some words just to fill this space Some words just to fill this space Some words just to fill this space Some words just to fill this space Some words just to fill this space Some words just to fill this space  Some words just to fill this space Some words just to fill this space Some words just to fill this space Some words just to fill this space ",
    },
    {
      name: "Apple",
      desc: "Laptop copmuter",
      price: 299,
      type: "laptop",
      url:
        "https://images.pexels.com/photos/3975677/pexels-photo-3975677.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940",
      path: "Apple",
      details:
        "Some words just to fill this space Some words just to fill this space Some words just to fill this space Some words just to fill this spaceSome words just to fill this space Some words just to fill this space Some words just to fill this space Some words just to fill this space",
    },
    {
      name: "Apple",
      desc: "Android",
      price: 299,
      type: "mobile",
      url:
        "https://images.pexels.com/photos/3975677/pexels-photo-3975677.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940",
      path: "Apple",
      details:
        "Some words just to fill this space Some words just to fill this space Some words just to fill this space Some words just to fill this spaceSome words just to fill this space Some words just to fill this space Some words just to fill this space Some words just to fill this space",
    },
  ]);

  return (
    <DataContext.Provider value={[data, setData]}>
      {props.children}
    </DataContext.Provider>
  );
};

Shop component:

function Shop() {
  let [data, setData] = useContext(DataContext);
  function mobileClick(e) {
    setData((prev) =>
      prev.filter((item) => {
        if (item.type === e.target.id) {
          return true;
        }
      })
    );
    console.log(data);
  }
  return (
    <div className="shopContainer">
      <div className="filter">
        <h1>Filter</h1>
        <form>
          <div>
            <label for="mobile">Mobile </label>
            <input type="checkbox" id="mobile" onClick={mobileClick} />
          </div>
          <div>
            <label for="mobile">Laptop </label>
            <input type="checkbox" id="laptop" />
          </div>
          <div>
            <label for="mobile">PC </label>
            <input type="checkbox" id="PC" />
          </div>
          <div>
            <label for="mobile">Touchpad </label>
            <input type="checkbox" id="Touchpad" />
          </div>
        </form>
      </div>
      <div className="main">
        <DataProvider>
          <Item />
        </DataProvider>
      </div>
    </div>
  );
}
3
  • Are you saying that after setData is called inside Shop, the UI doesn't reflect the change but the data does ? Commented Apr 11, 2021 at 17:57
  • Yes, that's what's happening. After the onClick function, the data gets changed and console log confirms that it has new state but the UI doesn't reflect that, it remains as the data initially was Commented Apr 11, 2021 at 17:58
  • Since data is an array, shouldn't you be passing an array into setData instead of a function? Commented Apr 11, 2021 at 18:10

2 Answers 2

1

Remove the additional DataProvider for Item. You already would have provided one in wrapping your whole app. Currently your Item is not receiving the updated data from that one instead it must be receiving the unchanged one from it's nearest DataProvider.

Shop should simply be :-

function Shop() {
  let [data, setData] = useContext(DataContext);
  function mobileClick(e) {
    setData((prev) =>
      prev.filter((item) => {
        if (item.type === e.target.id) {
          return true;
        }
      })
    );
    console.log(data);
  }
  return (
    <div className="shopContainer">
      <div className="filter">
        <h1>Filter</h1>
        <form>
          <div>
            <label for="mobile">Mobile </label>
            <input type="checkbox" id="mobile" onClick={mobileClick} />
          </div>
          <div>
            <label for="mobile">Laptop </label>
            <input type="checkbox" id="laptop" />
          </div>
          <div>
            <label for="mobile">PC </label>
            <input type="checkbox" id="PC" />
          </div>
          <div>
            <label for="mobile">Touchpad </label>
            <input type="checkbox" id="Touchpad" />
          </div>
        </form>
      </div>
      <div className="main">
          <Item />
      </div>
    </div>
  );
}

Here is a codesandbox to see it (don't mind the css)

Edit Redundant Data Provider

Note :- : Also currently selecting mobile would set your state to the filtered array permanently which will not allow you to apply any further filters on the original array successfully. You would always need to maintain a copy of original array for filteration purposes.

Sign up to request clarification or add additional context in comments.

Comments

1

Sorry for the previous wrong answer so i edited this one.

Your issue is you are accessing the state outside of the Provider.

As you will need to wrap the Shop Component with the Provider first and then you will have to access the state inside it.

function App(){
  return (
    <Provider>
      <Shop />
    </Provider>
  )
}


function Shop(){
  const [state, setState] = useContext(defaultState);
  return (
     // YOUR REST JSX HERE...
  )
}

1 Comment

I've just tried that, but nothing changed

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.