Hooks has increasingly become a new trendy way to experience the beauty of React. This article gives you some advices on how to use Hooks properly, along with a detailed explanation and insight.

Advice #1: UseHook Appropriately

The React community has ever been so high when Hooks first came out. Hooks are cool! Hooks are trendy! Hooks is the future of React!

Some of my colleagues even attempted to migrate their project codebase to Hooks’ fantasy land. But be careful! Don’t use Hooks if you don’t understand the motivation why React team invented Hooks. Please spend at least 30 minutes reading and think deeply about it.

Here to sum up, I can give you 2 reasons why Hooks exists:

  • To extract stateful logic from a component, so it can be tested independently and reused easily
  • To offer an alternative to class, because this is full of confusion and surprise.

I admit that Hooks have fulfilled its duty and deserve praise. I do love Hooks! But my advice is if you don’t have any particular problem with those reasons mentioned above, and if your code is already concise and effective, then there is no need to rewrite all your components with React Hooks, unless you truly want to experiment with the hype.

Advice #2: React Hooks Will Not Replace Redux

Hooks are Great, but No.

Eric Elliott wrote an excellent article here to explain why Hooks is not an absolute replacement of Redux.

Hooks is a set of APIs (or functions) that helps you play with state and other React features. Meanwhile, Redux is an architecture that you use to organize your code and control the flow in a predictable manner.

When talking about Redux, we not just mention about a state management library, we mention about a huge Redux ecosystem with plenty of open source libraries and powerful tools to help you deal with side effects, immutability, persistence, …

Moreover, you can use Redux with Hooks together. So instead of reinventing the wheel, you can use both to achieve a greater good.

Advice #3: Avoid State Mutation

Similar to this.setState  in class component, you should not modify state directly:

const [user, setUser] = useState({name: "Jane"})// wrong
user.name = "John"// will not re-render
// because the reference of user is still the same
setUser(user)

Instead, always create a new state:

const [user, setUser] = useState({name: "Jane"})// will trigger re-render
setUser({...user, name: "Jane"})

Advice #4: Understand How Dependencies Array Works

Many React developers are used to component lifecycle, especially with componentDidMount and componentDidUpdate. So when learning Hooks, their first question usually is: “How to run this piece of code just one?”.

In other words, how to make useEffect run only one time after render (like componentDidMount). And the answer is dependencies array.

It’s the array you pass as the second argument to useEffect:

useEffect(() => {}), depArr)

Dependencies array is a list of values that are used in shallow comparison to determine when to re-run the effect. We can imagine a pseudo code like so:

// this aims to illustrate the idea.
// not the exact implementation of useEffect.
// the actual comparison algorithm React uses is Object.islastDeps = nulluseEffect = (func, deps) => {
  if (!deps)
    return func()

  if (!lastDeps) {
    lastDeps = [...deps]    // shallow copy
    return func()
  }

  for (i = 0; i < deps.length; ++i)
    if (lastDeps[i] !== deps[i])    // shallow compare
      return func()
}

Look at this pseudo implementation of useEffect, you can better understand why and when a useEffect will re-run in the following code:

// run every time after render
useEffect(() => {
  console.log('run effect')
})// run only one time after first render
useEffect(() => {
  console.log('run effect')
}, [])

In the code below, useEffect performs a referential equality check, so it cannot determine if any properties of user have changed or not.

const [user, setUser] = useState({name: "Jane"})// run after first render, and re-run when user changed
useEffect(() => {
  console.log('run effect')   // perform effect here
}, [user])...// press the button somewhere
onPress = () => {
  setUser({name: "Jane"})
}

Although name maintains the same value “Jane”, this will trigger a re-render and re-rerun the effect function.

Advice #5: Understand useCallback and useMemo

  • If you pass a function to a child component as callback, you should memoize that function with useCallback.
  • If you have data that is expensive to compute, you should memoize it with useMemo.

Example: Generate and display a random number.

Without useCallback :

  • anytime you click RandomButton , it calls setNumber , which triggers re-render on Container (see log)
  • when Container re-renders, it initiates a new randomize function, then pass this function down to RandomButton as prop.
  • RandomButton receives a new prop and decides to re-render (see log).
const Container = () => {
  const [number, setNumber] = useState(0)
  const randomize = () => setNumber(Math.random())  console.log("render Container")
  return (
      <>
        

{number}

<RandomButton randomize={randomize}/> ) }const RandomButton = ({randomize}) => { console.log(“render RandomButton”) returnrandomize}/> }

Now, with useCallback and React.Memo:

  • when Container re-renders, useCallback checks its dependencies array to determine whether to return the last memoized function or create a new one.
  • but in this case, we provide an empty array, which means useCallback will always return the same randomize function.
  • when passing randomize function as prop to RandomButton, with the help of React.Memo, it checks and sees that randomize prop is the same, so no need to re-render (see log).
const Container = () => {
  const [number, setNumber] = useState(0)
  const randomize = useCallback(() => setNumber(Math.random()), [])
  
  console.log("render Container")
  return (
      <>
        

{number}

<RandomButton randomize={randomize}/> ) }const RandomButton = React.memo(({randomize}) => { console.log(“render RandomButton”) returnrandomize}/> })

In this special occasion, we pass an empty array to useCallback because its memoized function () => setNumber(Math.random()) doesn’t need any extra information to execute.

But what if we want to use number state in the randomize function, like so:

() => setNumber(number + Math.random())

In this situation, randomize depends on number state to execute correctly. So we specify number as an dependency in useCallback:

const randomize = useCallback(
   () => setNumber(number + Math.random()), [number]
)

But still, this may not be a perfect solution because when randomize calls setNumber, it will update number with a new value, then useCallback checks that its dependencies have changed and create a new randomize function, resulting in an unnecessary re-render of RandomButton again.

In order to deal with this dilemma, we can use functional updates. This is especially useful when the new state is computed using the previous state.

A perfect solution is as follow:

const randomize = useCallback(
   () => setNumber(number + Math.random()), [number]
)

Sourcehttps://medium.com/@blueish/5-advices-when-using-react-hooks-e476bbd160c4

.Net Development Companies

Related articles

When Should You Rebuild vs. Refactor? A Scoring Guide for Engineering Leaders
Methodology

When Should You Rebuild vs. Refactor? A Scoring Guide for Engineering Leaders

Not sure whether to rebuild or refactor your aging app? Use this practical 5-factor scoring framework to make a confident modernization decision.
Custom Software vs Off-the-Shelf Solutions: A Side-by-Side Evaluation Framework
Methodology

Custom Software vs Off-the-Shelf Solutions: A Side-by-Side Evaluation Framework

Most articles comparing custom software vs off-the-shelf solutions hand you a list of pros and cons and call it a day. That is not particularly helpful when you are trying to make a six-figure technology decision with three stakeholders in the room and a deadline in two quarters. The real question is not which option is “better.” It is the […]
Build vs Buy Software: How to Make the Right Decision for Your Business
Methodology

Build vs Buy Software: How to Make the Right Decision for Your Business

Build vs buy software is a strategic decision where businesses choose between developing custom software tailored to their specific needs (“building”) or purchasing existing SaaS solutions (“buying”). While often framed as a simple cost comparison, this choice directly shapes a company’s ability to innovate, scale, and compete. A poor build vs buy decision can increase […]
When a Dedicated Team Beats In-House Hiring
Methodology

When a Dedicated Team Beats In-House Hiring

Most companies default to hiring in-house because it feels safer. But with the average developer hire taking 35 to 45 days, and specialized roles stretching past 90 days according to LinkedIn’s 2024 Global Talent Trends report, that default can quietly cost you a product launch, a competitive window, or six months of payroll on a […]
Choosing Between Models: A Decision Framework for Tech Leaders
Methodology

Choosing Between Models: A Decision Framework for Tech Leaders

Many companies say they want to “outsource development,” but the needs behind that request are often very different. One company may need a full-time external team for a long product rebuild. Another may need a few developers temporarily to hit a deadline. A third may want a vendor to deliver a fixed-scope MVP. Same word […]
Dedicated Team Pricing in 2026: What Buyers in the US, EU, Australia, and Singapore Actually Budget
Methodology

Dedicated Team Pricing in 2026: What Buyers in the US, EU, Australia, and Singapore Actually Budget

Most pricing guides stop at a broad range, such as “$25 to $80 per hour.” That sounds useful, but in practice, it is not enough to plan a real budget. If you are evaluating a dedicated team in 2026, the better question is not “What is the hourly rate?” but “What does a stable, productive […]
No-Code vs Purpose-Built Software: A Decision Framework for Startup Founders
Methodology

No-Code vs Purpose-Built Software: A Decision Framework for Startup Founders

A practical decision framework for startup founders comparing no-code platforms and purpose-built software. Learn when each approach fits your stage, budget, and goals.
Software RFP Template: Free Guide + Download [2026]
Methodology

Software RFP Template: Free Guide + Download [2026]

A poorly written RFP wastes everyone’s time. You send it out, wait two weeks, and get back vague proposals that are impossible to compare. The problem isn’t the vendors. It’s the RFP itself. A strong software RFP template gives vendors the clarity they need to deliver accurate, comparable proposals. It sets expectations on scope, budget, […]
Cross Functional Team Roles and Responsibilities: A Practical Guide
Methodology

Cross Functional Team Roles and Responsibilities: A Practical Guide

Learn the key cross functional team roles and responsibilities that drive successful collaboration. Practical guide with role breakdowns and best practices.

Want to stay updated on industry trends for your project?

We're here to support you. Reach out to us now.

    Contact Message Box
    Back2Top

    Schedule a Demo with Our Industry Experts

    Book a free 30-minute call

    • See case studies aligned with your requirements
    • Validate our industry experience
    • Confirm technical fit for your project
    Schedule a Demo

      Your RFP, reviewed by experts in 24 hours

      AI-accelerated path from brief to working prototype. Engineers, not sales.
      • Clickable prototype of your core user flow
      • Workflow visualization mapping the full system
      • Architecture direction covering stack, integrations, and scale
      • Technical recommendation call with our engineering team
      Free Demo Campaign