3 min read

6 Most Useful React Hooks

Last Update: 13 May, 2022

Functional components are definitely my favourites type of react component. I find them easier to write and read. The minimum size of the boilerplate code necessary to get the compoennt up and running is also a lot smaller than the alternative. Hooks are going to be your biggest helper working with functional components.

§useState for State Management

Using this hook makes dealing with state in react so easy. Going through setState in class based components is also easy to create but not as easy and straight-forward as using a hook. This hook can be initialized with a state.

const [data, setData] = useState(0);

We will use setState in this way to, well set the state:

setState(newState);

We can set the state dynamically this way:

const NameChanger = ({name}) => { const [name, setName] = useState(name); return ( <> Count: {name} <button onClick={() => setName(name)}>Reset Name</button> <button onClick={() => setName("Slim Shady")}>Slim Shady</button> <button onClick={() => setName("Giovanna Giorno")}>Giovanna Giorno</button> </> ); }

We are setting the value of the for our name. And reset button will set the name to its initial value. Very simple and easy to read right? Manipulating the value of the state using the current value is also very easy. Adding this button to our component will help us just do that:

<button onClick={() => setName(prevName => prevName + "!")}>Add "!"</button>

With this button we are just adding "!" at the end of our name string. This prevName will help us replicate the merge behaviour of "setState" in class components:

setState(prevState => { // Object.assign would also work return {...prevState, ...updatedValues}; });

Well there we go, in my opinion this was actually 60% of what react is all about. If you have learned something from this part, good job!

§useEffect to the Rescue

This hook is the equivalent of componentDidMount, componentDidUpdate, and componentWillUnmount.

We handle subscriptions, timers, mutations, logging and side effects are supposed to be handled here using this hook. Side effect clean up is done in our return statement. An example will work better I guess:

useEffect(() => { const interval = setInterval(() => { console.log('This will run every second!'); }, 1000); return () => clearInterval(interval); }, []);

We are clearing the interval easily by returning it. We will see the log every second and when the component "mounts" we are clearing it up with "clearInterval()".

We can define a condition for firing up our useEffect. useEffect waits for the change in our conditions array and fires up when the condition changes:

useEffect(() => { console.log("condition changed") }, [condition])

You can create as many useEffects as you want. Whatever may be their role or functionality.

§Keep A Consistent Theme with useContext

React Context API is a lifesaver when it comes to state management in big projects. You can think of Context API as a replacement for redux. With this hook you can reach the state and keep a user or a consistent theme in your react projects.

We return the current context value for our specific context (MyContext) this way:

const value = useContext(MyContext);

If you somehow update the nearest js <MyContext.Provider> above the component, this Hook will trigger a rerender with the latest context value passed to that MyContext provider.

I'm directly copying the example given in the official react docs. I could not come up with a better example that could explain the usage of this hook.

const themes = { light: { foreground: "#000000", background: "#eeeeee" }, dark: { foreground: "#ffffff", background: "#222222" } }; const ThemeContext = React.createContext(themes.light); function App() { return ( <ThemeContext.Provider value={themes.dark}> <Toolbar /> </ThemeContext.Provider> ); } function Toolbar(props) { return ( <div> <ThemedButton /> </div> ); } function ThemedButton() { const theme = useContext(ThemeContext); return ( <button style={{ background: theme.background, color: theme.foreground }}> I am styled by theme context! </button> ); }

§Prevent Content Flashes with useLayoutEffect

Have you ever had a problem with some content that had to dynamically change and you were showing the user something that they were not supposed to see, for a split second ? If your answer is yes, this is the hook for that will solve your problem.

There is only one difference between useEffect and useLayoutEffect, useLayoutEffect fires synchronously after all DOM mutations. Updates scheduled inside useLayoutEffect will be flushed synchronously, before the browser has a chance to paint. You want use this hook to avoid getting those dreaded flushes of content in our DOM.

If you are more accustomed to using class based components, think of this Hook as the equivalet of componentDidMount and componentDidUpdate.

In server-rendering react will warn you when you use useLayoutEffect. Because useLayoutEffect cannot run until Javascript is downloaded.

Just keep in mind that useLayoutEffect is a little trickier to use than useEffect. Use useEffect whenever it's interchangeable. Most of the time you will need useEffect anyways.

§Easy Caching Using useSwr

You can get this hook by installing the swr package.

npm i swr

Think of this Hook as a neat way to handle caching in react easily. The name "SWR" derives from "stale-while-revalidate". SWR first returns the data from cache (stale), then sends the request (revalidate), and finally comes with the up-to-date data again. You can read the official documentation here.

import useSWR from 'swr' function Profile() { const { data, error } = useSWR('/api/user', fetcher) if (error) return <div>failed to load</div> if (!data) return <div>loading...</div> return <div>hello {data.name}!</div> }

This hook takes two arguments. The "key" and the "fetcher" function. The key will be used as a unique identifier and the fetcher will return data and error objects. Key is usually the url of the API we would like to use.

"data" value is undefined until the request is finished. When it finishes it's either data or error.

For fetcher feel free to use your favourite data-fetching library, it can be asynchronous.

A simple example from official docs:

import useSWR from 'swr' function Profile() { const { data, error } = useSWR('/api/user', fetcher) if (error) return <div>failed to load</div> if (!data) return <div>loading...</div> return <div>hello {data.name}!</div> }

§useRef to Focus and Persist

There are many use cases for this particular Hook.

useRef can be initialized with a value:

const refContainer = useRef(initialValue);

This is another example to its usage. The value will persist between re-renders cause by state changes. So you could keep a count in this manner by using this hook.

const MyComponent = () => { const ref = useRef({ count: 0 }); // every re-render causes the number to go up by one ref.current.count += 1; // you can also increment the count using this method const incrementCount = () => { ref.current.count += 1; } return <>Hello world</>; }

This value will be kept after state changes and re-renders. I'm sure you can think of couple of scenarios that this hook can come in handy.

useRef Hook is generally used to access a child:

function TextInputWithFocusButton() { const inputEl = useRef(null); const onButtonClick = () => { inputEl.current.focus(); }; return ( <> <input ref={inputEl} type="text" /> <button onClick={onButtonClick}>Focus the input</button> </> ); }

This way, clicking on the button will allow us to focus on the input directly. You can use this focus method in a useEffect Hook and you have a form that is ready to be written.

Ilker Akbiyik