kentcdodds / use-deep-compare-effect

🐋 It's react's useEffect hook, except using deep comparison on the inputs, not reference equality
https://npm.im/use-deep-compare-effect
MIT License
1.88k stars 84 forks source link

How can I force call useDeepCompareEffect? #46

Open rostgoat opened 3 years ago

rostgoat commented 3 years ago

Relevant code or config

ParentFile.jsx


  const params = useParams()
  const useForceUpdate = () => useState()[1]
  const forceUpdate = useForceUpdate()
  const [tripItems, setTripItems] = useState({})
  const [loading, setLoading] = useState(false)
  const [currentTrip, setCurrentTrip] = useState({ trips_locations_items: [] })

  // grab user from state
  const { user } = useSelector(state => state.user)

  useDeepCompareEffect(async () => {
    console.log('useDeepCompareEffect')
    setLoading(true)

    try {

      const trip = await findOneByShortUidOrUid({
        short_uid: params.trip_uid,
        user_uid: user.uid,
      })

      setCurrentTrip(oldTrip => ({ ...oldTrip, ...trip }))

      setupGrid()
      setLoading(false)
    } catch (error) {

    }
  }, [params, currentTrip])

  return (
    <div className={classes.container}>
      {loading && !_.isNil(currentTrip) ? (
        <p>Loading...</p>
      ) : (
        <Tabs>

          <TabList
            className={classes.tabsList}>
            <Tab
              onClick={forceUpdate}
              className="react-tabs__tab"
              selectedClassName="react-tabs__tab--selected-custom">
              A
            </Tab>
            <Tab
              className="react-tabs__tab"
              selectedClassName="react-tabs__tab--selected-custom">
              B
            </Tab>
          </TabList>

          <TabPanel>
            <A />
          </TabPanel>
          <TabPanel>
            <B />
          </TabPanel>
        </Tabs>
      )}
    </div>
  )

What you did:

I am using react-tabs to render 2 tabs: A and B.

When I initally load the page, by default, Tab A loads and called useDeepCompareEffect, which calls my API, gets a deeply nested object and adds to local state.

Then I click B, and do some stuff there and at some point I want to go to back to A. However, when I go back to A, I would like to call the API again to get any new changes.

I took a look at the following article about force re-rendering a component but I am not able to do so here (hence the onClick={forceUpdate}).

How can I force call useDeepCompareEffect when I click on A?

ioss commented 3 years ago

Just as a note: It seems, that the dependencies should be [params, user] not [params, currentTrip], as you are changing the currentTrip inside of that effect.

Now two proposals: 1) extract the effect callback and use it for useDeepCompareEffect, but also just call it directly as the onClick handler. 2) Or have (for example) an incrementing counter state ("refreshCounter"), that you can increment every time you want that effect to be executed – like in onClick of A – and add that counter to the dependencies: [params, user, refreshCounter]