DEV Community

Zach
Zach

Posted on

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)