0

I wanted to ask if there's a proper way of handling a situation when we have an useEffect that we only care it runs when one variable of the dependency array is changed.

We have a table that has pagination and inputs to filter the content with a button.

When the user changes the action (inputs) we update this state and when the user press search we fetch from the api.

When we have results paginated, we then hook on the page and if it changes we then fetch the corresponding page.

I solved the issue by having the ref of action and checking if the previous value was different from the current value. Though I don't know if this is the best practice

I did something like this.

const FunctionView = () => {

 const actionRef = useRef({})

 // action object have query params for the api

 const fetchData = useCallback((page) => {
  // call and api and sets local values
 }, [action])

 // this hook handle page next or previous
 useEffect(() => {
   let didCancel = false
   if (isEqual(Object.values(action), Object.values(actionRef.current))) {
     if (!didCancel) fetchData(page + 1)
   }
   actionRef.current = action
   return () => {
     didCancel = true
   }
 }, [page, fetchData, action])
 return (
  <>
    Components here that changes {action} object, dates and category
   <Button onClick={() => fetchData(page)}>Search</Button>
   <Table>...</Table>
  </>
)

}

I know I can set the dependency array to only page but react lint plugin complains about this so I ended up with warnings.

Reston
  • 3
  • 3
  • Does this answer your question? [How to fix missing dependency warning when using useEffect React Hook?](https://stackoverflow.com/questions/55840294/how-to-fix-missing-dependency-warning-when-using-useeffect-react-hook) – Mike Mar 09 '21 at 22:11
  • I agree with first comment that having fetchData inside useEffect would be for best. However, it appears you would still have ‘action’ dependency, correct? Looking at the code, this seems fine. – Nathan Hall Mar 09 '21 at 22:16
  • Also, you can ignore the lint rule with comment. However, this is normally not a good idea – Nathan Hall Mar 09 '21 at 22:17
  • @Mike Sorry It don't. The thing is I need to be able to run the effect when the page changes but no other inputs like dates and category. But if the users click search then It would run the function that fetch the data, the same that useEffect uses when updating the current page. – Reston Mar 10 '21 at 12:36

1 Answers1

0

A common mistake is trying to directly wire the state of forms up to the data they represent. In your example, you DO want to perform the search when action changes. What you're actually trying to avoid is updating action every time one of the inputs changes prior to submit.

Forms are, by nature, transient. The state of the form is simply the current state of the inputs. Unless you really want things to update on every single keystroke, the storage of these values should be distinct.

import { useCallback, useEffect, useState } from 'react'

const Search = () => {
  const [action, setAction] = useState({})

  const loadData = useCallback(() => {
    // call api with values from `action`
  }, [action])

  useEffect(loadData, [loadData])

  return (
    <>
      <SearchForm setRealData={setAction} />
      <Table>...</Table>
    </>
  )
}

const SearchForm = ({ setRealData }) => {
  // don't want to redo the search on every keystroke, so
  // this just saves the value of the input
  const [firstValue, setFirstValue] = useState('')
  const [secondValue, setSecondValue] = useState('')

  const handleFirstChange = (event) => setFirstValue(event.target.value)
  const handleSecondChange = (event) => setSecondValue(event.target.value)

  // now that we have finished updating the form, update the state
  const handleSubmit = (event) => {
    event.preventDefault()
    setRealData({ first: firstValue, second: secondValue })
  }

  return (
    <form onSubmit={handleSubmit}>
      <input value={firstValue} onChange={handleFirstChange} />
      <input value={secondValue} onChange={handleSecondChange} />
      <button type="submit">Search</button>
    </form>
  )
}
Eric Haynes
  • 5,126
  • 2
  • 29
  • 36
  • 1
    "the storage of these values should be distinct." this helped me a lot by seeing the problem from a different perspective. Thanks @erick2k8 So I ended up with a useEffect with action and page as dependencies and function to handle the form submit. – Reston Mar 10 '21 at 13:29