5 minutes guide to custom React hooks

If you are new to react, you might want to start here: Cheat sheet to common React terms

Short intro to react hooks

The React team is continously improving the developer experience. One feature that has drastically improve our React code base is React hooks. React hooks have been out for more than a year.

Hooks let you split one component into smaller functions based on what pieces are related (such as setting up a subscription or fetching data), rather than forcing a split based on lifecycle methods.
-- React documentation

The motivation behind react hooks is:

  • Allow ease of reuse of stateful logic bewtween components
  • Better cohesion. With the class components and the use of lifecycle, related code might be separated and unrelated code are combined together.

Code composability

When developing with React, we are encourage to develop components that are easy to compose/ use in different parts of the softwares. Translate to quantifiable terms, we create reusable components that could help us to reduce the time and cost of development in the long run. So that we could go home on time and companies are happy that software gets delivered on time.

When I think of code composability, I like to think about lego blocks. By putting these simple lego blocks together, we could create a massive and stable architecture. If we look at the term compose, the antonym is decompose. In that sense, we can think of how we could break down a massive component into their logical smaller components. Or we could also upright identify the lowest denominator of the various components and work upwards. I usually use a combination of two.

-- Brad Frost

There are many React UI libraries, like Material-UI, Ant Design and React Bootstrap that showcase this principle.

At this point in time, you might be thinking, what have this to do with react hooks? Aren't we diverging from the main topic of the article? We are going to look into how we can combine our UI components with reusable react hooks to build up a stateful component.

Learning from open-source projects.

I learn many of the possibilities of react hooks through the open source react hooks packages. Here are a few projects that I recommend to look into:

Code

Let's say you have a simple datatable component: Table, which takes a data and columns props.

const data = [
  {name: 'Jelly', breed: 'Chihuahua', age: 5}, 
  {name: 'Cookie', breed: 'Border Collie', age: 11}
]

columns = [
  {
    dataKey: 'name',
    key: 'name',
  },
  {
    dataKey: 'breed',
    key: 'breed',
  },
]

const MyReactTable = () => {
  return (
    <Table data={data} columns={columns}>
  )
}

Your boss is happy, and ask you to create a similar UI table for customer, cats and hamsters. Obviously, you could use the same Table to meet the requirements.

Then one day, your boss comes to tell you that the user need to trigger a cell highlight on the table for the dogs and cats tale to show animals over 7 years old. And for the customers, you need to create a cell highlight for customers that haven't visited the shop for more than 6 months but less than 1 year.

The common denominator will be the method to trigger a highlight. We will make the assumption that the datatable will have a rowRenderer props that allows you to customise individual row

There are 2 things we need to achieve:

  • State of trigger
  • Method to trigger the highlight
const useCellHighlight = (callback) => {
  const [isHighlighted, toggleHighlight] = useState(false); 

  const renderRows = useCallback((rows) => {
    if(!isHighlighted) {
      return rows; 
     }

    return rows.map(singleCell => 
      callback(singleCell)
    }
  }, [isHighlighted])

  return { renderRows, toggleHighlight }
}

Over at the different tables, we will implement the useCellHighlight hook with their respective call back function.

const AnimalWithAgeIndicator = () => {
  const { renderRows, toggleHighlight } = useCellHighlight(renderSingleCell)

  function renderSingleCell({ cell, rowData }) {
    const { age } = rowData; 
    if(age > 7) {
      return cloneElement(cell, {style: { background: 'red' }}); 
    }

    return cell; 
  }

  return (
    <>
      <button onClick={toggleHighlight}>Show old animals
      <Table data={data} columns={columns} rowRenderer={renderRows}>
    </>
  )
}

For the customer, it will take a similar structure, except we will pass a different call back function.

const customerData = [
  {name: 'Jane', monthsNotVisited: 9}, 
  {name: 'Sally', monthsNotVisited: 3}
]

const columns = [
  {
    dataKey: 'name',
    key: 'name',
  },
]

const UserWithIndicator = () => {
  const { renderRows, toggleHighlight } = useCellHighlight(renderSingleCell)

  function renderSingleCell({ cell, rowData }) {
    const { monthsNotVisited } = rowData; 
    if(monthsNotVisited > 6 && monthsNotVisited <= 12) {
      return cloneElement(cell, {style: { background: 'red' }}); 
    }

    return cell; 
  }

  return (
    <>
      <button onClick={toggleHighlight}>Show customer to follow up
      <Table data={customerData} columns={columns} rowRenderer={renderRows}>
    </>
  )
}

So this is one simple example of how you can create your own custom hooks in React. Some other common use cases to implement custom hooks are user authentication, API fetches and their side effects and media resize.

Join the geek movement

Get updated with our latest posts