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})
})
}
}
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):
- Call
useEffect
- Call data
- Render component (which triggers 'useEffect')
- Call
useEffect
- 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'}/>)} />
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} />
Way simpler.
Top comments (0)