React Hooks — advantages and comparison to older reusable logic approaches in short

Mateusz Roth
6 min readJun 15, 2019

--

This post requires basic knowledge of React Hooks and of terms like Higher Order Components and Render Props. It shows few examples presenting advantages of React Hooks.

React Hooks advantages

  • hooks are easier to work with and to test (as separated functions from React components*) and make the code look cleaner, easier to read a related logic can be tightly coupled in a custom hook. Check below visualization of differences between standard stateful component and a one using hooks:
  • * by separated functions I mean writing a logic as your own hooks that are just functions that return values or functions used for accessing and manipulating state with use of standard React hooks. We still have to test them through a mock React component but I think it’s more readable and easier than testing HOCs:
// an example hook to test, https://medium.com/@nitinpatel_20236/unit-testing-custom-react-hooks-caa86f58510import React, { useState } from 'react';export const useTextField = name => {
const [value, setValue] = useState('');
const onChange = event => {
setValue(event.target.value);
};
return {
name,
value,
onChange,
placeholder: name,
};
};
const InputDemoWithHooks = () => {
const nameField = useTextField('name');
return <input type="text" {...nameField} />;
};
export default InputDemoWithHooks;

And tests for the hook:

// test for previous hook, https://medium.com/@nitinpatel_20236/unit-testing-custom-react-hooks-caa86f58510// file './testUtils';
import React from 'react';
import { mount } from 'enzyme';
const TestHook = ({ callback }) => {
callback();
return null;
};
export const testHook = (callback) => {
mount(<TestHook callback={callback} />);
};
// tests
import { act } from 'react-dom/test-utils';
import { testHook } from './testUtils';
import { useTextField } from '../InputDemoWithHooks';
let nameField;
beforeEach(() => {
testHook(() => {
nameField = useTextField('name');
});
});
describe('useTextField', () => {
test('should have an onChange function', () => {
expect(nameField.onChange).toBeInstanceOf(Function);
});
test('should have correct name', () => {
expect(nameField.name).toBe('name');
});
test('should update the value when onChange is called', () => {
act(() => {
nameField.onChange({ target: { value: 'nitin' } });
});
expect(nameField.value).toBe('nitin');
});
});
  • code that uses hooks is more readable and have less LOC (lines of code), let’s look on a standard class component example:
// example class component that we will rewrite as function component, https://m.habr.com/en/post/443500/class Form extends React.Component {
constructor(props) {
super(props);
this.saveToDraft = debounce(500, this.saveToDraft);
};
state = {
// Fields values
fields: {},
// Draft saving meta
draft: {
isSaving: false,
lastSaved: null,
},
};
saveToDraft = (data) => {
if (this.state.isSaving) {
return;
}
this.setState({
isSaving: true,
});
makeSomeAPICall().then(() => {
this.setState({
isSaving: false,
lastSaved: new Date(),
})
});
}
componentDidUpdate(prevProps, prevState) {
if (!shallowEqual(prevState.fields, this.state.fields)) {
this.saveToDraft(this.state.fields);
}
}
render() {
return (
<form>
{/* Draft saving meta render */}
{/* Inputs render */}
</form>
);
};
}

And the same component as above rewritten as function component:

// the above class component rewritten as function component, https://m.habr.com/en/post/443500/const Form = () => {
// Our state
const [fields, setFields] = useState({});
const [draftIsSaving, setDraftIsSaving] = useState(false);
const [draftLastSaved, setDraftLastSaved] = useState(false);
useEffect(() => {
const id = setTimeout(() => {
if (draftIsSaving) {
return;
}
setDraftIsSaving(true);
makeSomeAPICall().then(() => {
setDraftIsSaving(false);
setDraftLastSaved(new Date());
});
}, 500);
return () => clearTimeout(id);
}, [fields]);
return (
<form>
{/* Draft saving meta render */}
{/* Inputs render */}
</form>
);
}
  • thanks to hooks it’s easy to make code more reusable / composable (also they don’t create another element in DOM like HOCs do) — with HOCs we are separating unrelated state logic into different functions and injecting them into the main component as props, although with Hooks, we can solve this just like HOCs but without a wrapper hell. Let’s compare below example:
example reusable logic for liking posts on a feed implemented as HOC, https://hackernoon.com/why-react-hooks-a-developers-perspective-2aedb8511f38

And the same logic rewritten with use of hooks:

example reusable logic for liking posts on a feed implemented as React Hooks, https://hackernoon.com/why-react-hooks-a-developers-perspective-2aedb8511f38
  • you can define several separated lifecycle methods instead of having all in one method (so you can split componentDidMount logic with ease). Compare examples below:
standard componentDidMount method, https://hackernoon.com/why-react-hooks-a-developers-perspective-2aedb8511f38
componentDidMount rewritten for React Hooks, https://hackernoon.com/why-react-hooks-a-developers-perspective-2aedb8511f38
  • hooks are going to work better with future React optimizations (like ahead of time compilation and components folding) — components folding might be possible in future (https://github.com/facebook/react/issues/7323) — what means dead code elimination at compile time (less JS code to download, less to execute)
  • even now, minification of functions in JavaScript is much better than minification of JavaScript classes. It’s not possible for example to minify method names of JS classes as every method can be either private or public, so we don’t know when it’s used outside the class. Less code to download, process and execute has positive impact for end user. Check comparison:
comparison between minification of class component and function component that uses hooks, https://typeofweb.com/2019/02/04/react-hooks-wprowadzenie-i-motywacja/
  • hooks show real nature of React which is functional, using classes make developer easier to do mistakes and use React anti-patterns. In my career I encountered examples where people with object-oriented programming background tended to extend class components… that were hard times for debugging
  • hooks are very convenient to re-use stateful logic, this is one of their selling point. But this not applicable when app is built using some state management library and stateful logic doesn’t live in React components. So for an app on which I work in its current state hooks are mostly for readability and to make it future-proof because for local logic we use MobX stores

React Hooks vs older approaches for reusable logic

  • Read code examples and think of differences in implementing logic between in a Class Component:
  • and as Mixins (deprecated):
  • and as HOCs (Higer Order Components):
  • and as Render Props:
  • and as Hooks:

Mixins are deprecated API. HOCs disadvantage is they create additional DOM elements so when you use few HOCs, then you will see your component nested in few DOM elements. Render props if nested are creating similar structures as “callback hell” in the past. Hooks have no disadvantages of using multiple custom hooks on a single component.

For interested people more detailed comparison information can be found on the blog post by Ryan Yurkanin: https://www.freecodecamp.org/news/why-react-hooks-and-how-did-we-even-get-here-aa5ed5dc96af/ .

Sources

--

--