0

The issue I am having is in the change() function. I want to call filteredData() function after the setState runs. Usually, I would use a callback function to call filteredData, but useState doesn't allow callbacks. I can't use useEffect because it will call the function initially before there is any data change.

import React, { useState, createContext, useEffect } from "react";
import data from "../Reducers/ListingsData";

   export const GlobalContext = createContext();

   export function GlobalProvider({ children }) {
     const [state, setState] = useState({
      name: "",
      city: "all",
      homeType: "all",
      rooms: 0,
      bathrooms: 0,
      min_price: 0,
      max_price: 10000000,
      min_floor_space: 0,
      max_floor_space: 40000,
      finished_basement: false,
      swimming_pool: false,
      garage: false,
      data: data,
      filteredData: data,
      populateFormsData: "",
      sortby: "price-dsc",
      search: "",
   });

  function change(event) {
    let name = event.target.name;
    let value =
    event.target.type === "checkbox"
    ? event.target.checked
    : event.target.value;

  setState((prevState) => ({ ...prevState, [name]: value }));
  filteredData();
 }

   function filteredData() {
    console.log(state);
}

  return (
   <GlobalContext.Provider value={{ state: state, change }}>
     {children}
   </GlobalContext.Provider>
 );

}

tjsims8819
  • 61
  • 1
  • 5
  • Does this answer your question? [How to use \`setState\` callback on react hooks](https://stackoverflow.com/questions/56247433/how-to-use-setstate-callback-on-react-hooks) – Matt U Jun 13 '21 at 14:15

5 Answers5

0

If you would like to run something whenever state changes, you can use a useEffect hook that has state in the dependency array:

useEffect(() => {
  console.log(state);
}, [state]);

If you just need to condition off of a property within your state object, you can just have that property in the dependecy array:

useEffect(() => {
  console.log(state.name);
}, [state.name]);

If you'd like to keep using the filterData function, it might be best to define it within the effect so you don't have to list it as a dependency in the dependency array:

useEffect(() => {
  function filterData() {
    console.log(state);
  }
  filterData();
}, [state]);

If you need to define the filterData function outside the effect for whatever reason, then you should probably use a useCallback hook to keep the same function reference whenever state is the same, and only change it when state is updated:

const filterData = useCallback(() => {
  console.log(state);
}, [state]);

useEffect(() => {
  filterData();
}, [filterData]);
Nick
  • 16,066
  • 3
  • 16
  • 32
0

This worked for me. I needed to find away to use useEffect without the initial run.

const { useState, useRef, useLayoutEffect } = React;

function ComponentDidUpdateFunction() {
 

 const firstUpdate = useRef(true);
 useLayoutEffect(() => {
   if (firstUpdate.current) {
   firstUpdate.current = false;
  return;
}

filteredData();

});

tjsims8819
  • 61
  • 1
  • 5
0

arent you overcomplicating it. I use a very simple approach

 export function GlobalProvider({ children }) {
     const [state, setState] = useState({
      name: "",
       ......
      search: "",
   });

  function change(event,'pass name of field as second argument') {
    //let name = event.target.name;
    //let value =
     //event.target.type === "checkbox"
    //? event.target.checked
    //: event.target.value;
      
      //create the copy of the state object
      let copyState=state
      //modify the new object with value and use second arg for getting key name
      copyState['second argument aka name in this case']= event.target.value
       //save to state
      setState(copyState)
      
      filteredData();
     }

this way you dont need to worry about overwriting the previous values if that is what you are trying to attempt

Swagath Shetty
  • 153
  • 1
  • 2
  • 9
-1

In your particular case, You can check when your name changes, then run it inside the useEffect() hook:

useEffect(() => filteredData(), [state.name]);

For further reference see How to use setState callback on react hooks

Shivam Jha
  • 3,160
  • 3
  • 22
  • 36
  • I'd recommend cleaning up this answer a bit. If anything is returned from the `useEffect` callback function, it should be a cleanup function. As-is, you're returning the return value of `filteredData`, which I guess we're fortunate isn't returning anything right now. Additionally, your dependency array is not comprehensive, it's missing `filteredData` and risks containing a stale reference. – Nick Jun 13 '21 at 14:07
-1

Best way to do it is using useEffect and adding your state to the dependency array.

Rather than calling filteredData() within change function you can call it from useEffect and add state to the dependency array of your useEffect. So,anytime your state is updated your useEffect is triggered.

useEffect(() => {
    filteredData();
  }, [state])
PRATIK NAIK
  • 489
  • 3
  • 7
  • Your dependency array is incomplete and risks having a stale reference to `filterData` – Nick Jun 13 '21 at 14:14