DEV Community

Zach
Zach

Posted on

1 1

Hooks

This post has been backlogged for a few days. Nearly all of it was written this past Sunday (8/1).

In this post:

Refactoring the refactor

I set off this morning to refactor some sparse front-end code. My goal was to turn a class based, stateful component, into a hook-equipped, functional component. While I didn't necessarily expect it to take much time - the fact that it ate away into the early afternoon didn't shock me. What did come as a surprise was that I ended up refactoring a significant element of my first refactor, bringing it back around to resemble its earlier state. It was a winding process, but I learned quite a bit while navigating hooks, routes, and the React way.

Infinite Loops and useEffect dependencies

After the initial class/state -> functional/hook conversion looked up-to-form (the result of which follows this sentence), I ran a test by refreshing the browser, hoping that the transformation would be seamless.

//index.jsx
<Router>
  <Switch>
    <Route path="/all" exact component={Feed} />
    <Route path="/:user/feed" exact component={Feed} />
    <Route path="/:user/post/:post_id " exact component={(props) => <Post {...props}/>} />
  </Switch>
</Router>

//feed.jsx
 componentDidMount(){
    const path = this.props.match.path

    if (path === "/all"){
      httpHandler.getFeedAllUsers((err, data)=>{
      this.setState({postData:data})
      })
    } else if (path === "/:user/feed"){
        const user = this.props.match.params.user
        httpHandler.getFeedOneUser(user, (err, data)=>{
        this.setState({postData:data})
      })

    }
  }
Enter fullscreen mode Exit fullscreen mode

Instead what I saw was an infinite loop of 'get' calls being made by the useEffect hook. Essentially the cycle looked like this (this is, my 100% faulty understanding):

  1. Call useEffect
  2. Call data
  3. Render component (which triggers 'useEffect')
  4. Call useEffect
  5. repeat

How to break this cycle? First, I did a bit of reading to understand the problem. This post does a great job of explaining the issue and the solution.

What I needed to do was give React a change to observe - a change that would trigger useEffect. Without it, useEffect would only be called when Feed was mounted. And since Feed isn't re-mounted by a changed url, it doesn't call the data-fetcher that creates the state change that renders the correct data from the new url. Essentially I was facing the opposite of an infinite loop - a loop I couldn't get into. There was no call to the data-fetcher inside of that function.

What I landed on was using a prop to indicate that the feed being requested had changed. From one of 'user posts' or 'all posts' to the other. Passing that prop as a dependency into useEffect would signal - on a change - to useEffect to fetch fresh data.

The resulting <Route/> component looked like this:

<Route path="/all" render={(props)=>(<Feed {...props} feedView={'all'}/>)} />
Enter fullscreen mode Exit fullscreen mode

Now as I type this, I wonder if I could have just passed in a Router parameter like 'path' as a dependency. Were that to work, I could avoid that re-refactor I performed and go back to the simpler refactor that passed only a component into the <Route/> as a prop. Compare the above code snippet to this:

<Route path="/all" component={Feed} />
Enter fullscreen mode Exit fullscreen mode

Way simpler.

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more