React Hooks are a powerful technique liked by many developers. Why? There are so many reasons for that. One of them is that this feature . I'd like to talk about the most common hooks and present some tips about using them to improve app performance. So, let's get started. extended the use of functional components The basics First off, you should know that . They allow using some React features in function components like state managing or use of lifecycle methods. However, you should keep in mind that they should be called only on the top level, so you can't call a hook inside a conditional statement or loop. hooks are functions There are only two places where you can call the hook: or . While the first case is rather obvious, the second one is usually related to writing custom hooks which are a good way to share logic between components. inside function component inside another hook The variety I feel like I should also make a distinction between the hooks before I start writing about them. So, generally, we can divide them into and ones. To the first group, we rank: basic additional useState useEffect useContext While in the other set, we have: useCallback useMemo useReducer useRef useImperativeHandle useLayoutEffect useDebugValue In this article, I intend to focus on the most common ones, so if you're interested in the rest of them, you should read . You'll find a description of all React Hooks, good practices and answers for frequently asked questions. Hooks API Reference useEffect Let's start with useEffect. This hook accepts 2 arguments - the first is a and the second is an array called . function, dependencies Dependencies are optional, and the default value is null. The passed function will be executed each time after the component's mount or when some value in the dependencies array changed. There are also two options in this hook. If you pass an empty array as dependencies, useEffect will be executed once during the first component's render. But, if your function passed to useEffect Hook returns a function, it will be executed during unmount component phase. Just like this: useEffect( { subscription = subscribeSomething(); subscription.unsubscribe(); }, [...deps]) => () const return => () How to apply useEffect Now that you know it let's move on to some good practices of using this hook. If you want to do some action after the component renders, you should pass the empty array as dependencies. It's a good place for data fetching, subscribing, and many more. only once Remember to release memory and clean after useEffect execution when the component unmounts. It's a good practice that will also ensure no memory leaks. If a function called inside of useEffect uses another variable, that variable should be included in dependencies, and these dependencies should contain only values from the component's scope. Define functions that aren't executed anywhere else inside useEffect. Thanks to this, you don't have to pass function reference into dependencies. useCallback It's used to prevent redeclaring functions in the component's definition. Hence, it won't create new references for them. Using useCallback is similar to useEffect – we have a and . function dependencies fn = useCallback( { }, [...deps]) const => () // fn definition If you don't use useCallback, after component's render fn would be a new reference. There's no problem if it's the first render since a new reference just will be created. But in every next render, the old reference will be cleaned by the garbage collector, and fn would be a new reference. You may wonder now why we have to useCallback if the old reference will be cleaned anyway. What's the point, right? The answer is that if you put fn in another hook dependencies, it'll be recognized as a change. The result? Using useCallback everywhere to keep references may be nonoptimal. useMemo This hook allows programmers to use a technique called . What's that for? Let's assume you have a function that contains expensive computation. In some cases, it can be called multiple times with the same set of arguments, such as user clicked next, then previous, then next. If we memoize arguments and the result of a particular function call, we don't have to execute a whole function's code. We can just return a result. memoization But the hook has requirements: The function must be predictable. It means the result must be the same for a certain set of arguments. For example we know passing a = 2, b = 2 for function (a, b) => a + b will always return 4. The function cannot create side effects. It has to do the computation without modifying anything anywhere in the application. These principles are characteristic of a paradigm called . Applying useMemo is similar to working with other hooks – you need to pass a function and dependencies. However, you can also memorize a whole component using . Because function components are functions, they may also be pure functions. functional programming React.memo useState It's a hook for component local state managing. It works very simply, but I would like to consider the below example. Component: FunctionComponent<{ : string }> = { [isFetching, setFetching] = useState( ); [error, setError] = useState( ); [data, setData] = useState([]); useEffect( { setError( ); setFetching( ); fetchData() .then( setData(res.data)) .catch( setError(err.message)) .finally( setFetching( )) }, [id]); const id ( ) => { id } const false const null const => () null true => res => err => () false The main problem is that component will re-render whenever its state or props has been changed. In the example above, we use multiple useState Hooks to manage specific values. Below is the second approach. We can define a state as a single object and then mutate it. Component: FunctionComponent<{ : string }> = { [state, setState] = useState<State>({ : , : [] }); useEffect( { setState( ({ ...prevState, : , : })) fetchData() .then( setState({ : res.data, : })) .catch( setState({ : err.message, : , : [] })) }, [id]); const id ( ) => { id } const isFetching false data => () => prevState isFetching true error undefined => res data isFetching false => err error isFetching false data What do you think? Which approach is better? Should we always use a single object to minimize the number of renders? In my opinion, both are fine. It really depends on the case. For example, when you're facing some problems with re-renders, I'd try to use a single object. But if you have a simple state and it's easier for you, you can divide it into separate state values. The final decision is yours. In this case, I just wanted to show that there's no one recipe for writing optimal code and that there's no need to optimize everything in your application. Also, sometimes optimizations are done too early, which jeopardizes bringing the expected results. That's why I tend to focus on writing clean code and optimize things only when customer needs, wants or when we're facing some visible performance troubles. Final thoughts I hope you enjoyed this article about using React Hooks and good practices related to it. As you can see, hooks are a very useful technique, which changed stateless function components into "full-fledged" components extending them with lifecycles, element references, and state management. And, of course, they provide the opportunity for performance optimization. If you're interested in finding out more about the subject, visit our . There's plenty of information about React's components, libraries, and many more. blog This article was written by Wojciech Hanzel, FullStack Developer at Gorrion .