DEV Community

Kunoky
Kunoky

Posted on

What should I do if I want to call a function after a state change?

When I use hooks, I have an object obj that will be modified in multiple places. I just want to call a function that uses obj after a certain modification. If it is called directly, obj is not the latest value. What is the optimal solution?


const [obj, setObj] = useState({})

const funcA = () => {
  ajax(obj)
}

const funcB = (v) => {
  setObj(v)
  funcA()
}
// ...other setObj
Enter fullscreen mode Exit fullscreen mode

This is my current code, but there are some bug

const [obj, setObj] = useState({})

const funcA = () => {
  ajax(obj)
}

const funcB = (v) => {
  Object.assign(obj, v)
  setObj({...obj})
  funcA()
}
Enter fullscreen mode Exit fullscreen mode

Does React plan to implement a callback api similar to that after setState?

Top comments (3)

Collapse
 
lexiebkm profile image
Alexander B.K.

Did you consider using useEffect ?

I think you can use useEffect here. You can read in the section : https://reactjs.org/docs/hooks-faq.html#is-it-safe-to-omit-functions-from-the-list-of-dependencies
on how to use it in declaring and calling your funcA function such that it gets called only when the obj state changes.

Because I don't know from where your funcB is called, I leave its declaration as is.
By placing and calling the funcA in a useEffect with the right dependency, in this case your obj variable, the effect is that funcA gets called everytime the obj state changes.

const [obj, setObj] = useState({})

const funcB = (v) => {
  setObj(v)
}

useEffect(() => {
   // funcA should be placed in this useEffect
   const funcA = () => {
       ajax(obj)
    }

    funcA();
 }, [obj]);
Enter fullscreen mode Exit fullscreen mode
Collapse
 
kunoky profile image
Kunoky

For example, there is a page to query the list according to conditions. It looks like this

function List() {
  const [condition,setCondition] = useState({})
  const [data,setData] = useState([])
  useEffect(() => {
    listData()
  }, [condition])

  const listData = async () => {
    const res = await ajax(condition)
    setData(res)
  }
  return data
}
Enter fullscreen mode Exit fullscreen mode

Now we add a function to obtain conditions from the server during initialization

function List() {
  const [condition,setCondition] = useState({})
  const [data,setData] = useState([])
  useEffect(() => {
    getCondition()
  }, [])
  useEffect(() => {
    listData()
  }, [condition])

  const listData = async () => {
    const res = await ajax(condition)
    setData(res)
  }
  const getCondition = async () => {
    const res = await ajax()
    setCondition(res)
  }
  return data
}
Enter fullscreen mode Exit fullscreen mode

In this case, listData will be called twice during initialization. Obviously, the first time is useless

Collapse
 
kunoky profile image
Kunoky

Because there are many places to modify obj, but I only want to call the funcA after a certain modification, useEffect is not appropriate