How to use React Hooks with multiple API calls? - reactjs

I'm trying to understand how to use React Hooks in my new project and I'm looking for some guidance as I didn't find clear answer.
I have a form that requires data from 3 separate API calls. Currently I have created 3 hooks like useGetDataSource1, useGetDataSource2 and useGetDataSource3 that wrap API calls with useEffect. Also I've encapsulated usage of these 3 hooks in additional hook called useGetSettings with additional useEffect to separate this logic from form code. Is that correct? Or maybe I should create only one hook useGetSettings and keep data source logic separated in plain JavaScript functions?
I want to save data from this form when user presses Submit button. Should I use useCallback for it or I shouldn't use any hook at all? Currently I've created 4 hooks just like with getting data, but without any useEffect/useCallback.

useEffect is meant to control the side effects in functional components, in most cases; you shouldn't need to have a useEffect hook inside a hook that encapsulates another hook that uses useEffect
Most hooks are meant to set and get, for example:
useState hook can be used like:
const [count, setCount] = useState(0);
count is the variable you use to get the current state value
setCount is the setter; where you set the state value
Hooks are cool but do not hookify everything, check this article:
React hooks: not magic, just arrays
If you'd like to outsource complicated logic to another file and call it a hook; technically you may, but it's best to just call that functional, object oriented programming with separation of concerns, write tiny functions that does one thing, one thing only and does it perfectly, this way; when your code grows, your tiny functions will be easy to maintain with the power of emergence.

Related

Is useEffect inside custom hook considered a bad practice?

I was trying to create a reusable hook which includes 2 other mutation hook from react query which does 2 different operations. I was successfully able to create my custom hook and everything is working as expected. My only question is, while building the hook I had to use a useEffect inside my custom hook. I am just wondering if it is a bad practice to have a useEffect inside a custom hook and do I need to change my approach? Will there be any performance issue because of this? Is there something I should be aware of?
It's a very common thing to do. The official documentation describes a custom hook that uses useEffect.
The only thing you should be aware of is that, as always, your hook isn't supposed to intentionally break hook isolation by maintaining an arbitrary shared state outside the hook itself.
I think the "intentionally breaking hook isolation by maintaining an arbitrary shared state outside the hook itself" refers to what happened to me. I was storing a "variable" in the custom hook (with useState) but I was wanting that variable to be accessible in the outside React component, but sometimes the custom hook state was reset, so that value was also reset, and the React component would have suffered from this.
I think the general idea is to always maintain order, you define state in the outer hook/React component, pass that state into custom hooks, the custom hook can generate other data that can be returned as after some processing steps (like with useEffect) and the data can be used in the outer hook/React component as a "state generated by some initial state" which is persisted ONLY in the outer hook/React component caller.
So, in your case and mine, NEVER initialize & maintain an outer hook/React component caller state in the custom hook or NEVER modify the initial state given by the outer caller, in your custom hook.
Sorry, it might be confussing what I wrote, but this is still not very clear for me too. Hope it is clearer though than the short answer Igor gave you.
Good luck !

useEffect or useMemo for API functions?

which is the best hook for dispatching API calls in a component. Usually I use useMemo for calling the API on the first render, and useEffect if I need extra side effects, is this correct? Becouse sometimes I get the following error:
'''index.js:1 Warning: Cannot update a component (Inscriptions) while rendering a different component (PaySummary). To locate the bad setState() call inside PaySummary, follow the stack trace as described in ...''''
That happens when I route to a component and rapidly change to another one, it doesn't "affect" the general behaivour becouse if i go back to the previous component it renders as expected correctly. So how should I do it?
Calling an API is a side effect and you should be using useEffect, not useMemo
Per the React docs for useEffect:
Data fetching, setting up a subscription, and manually changing the DOM in React components are all examples of side effects. Whether or not you’re used to calling these operations “side effects” (or just “effects”), you’ve likely performed them in your components before.
Per the React docs for useMemo:
Remember that the function passed to useMemo runs during rendering. Don’t do anything there that you wouldn’t normally do while rendering. For example, side effects belong in useEffect, not useMemo.
Performing those side effects (and modifying state) during rendering or with useMemo is the reason you encounter the errors you mention.
basically I rather to use useEffect in componentDidMount manner, with no dependency like below
useEffect(() => {
// Api call , or redux async action here...
}, [])
for calling api's at component mount state.
most of the time i find my self using useMemo for memoising the data at functional Component render level, for preventing the variable re-creation and persist the created data between renders except the dependency changes.
but for the context of your question, there is a hook called useLayoutEffect which is primarily used for actions to happen before painting the DOM, but as i said basically most of the time in projects i find calling apis in a simple useEffect with no dependencies aka, the did mount of your component, in order to load the required data for component!
A bit late but, while everything mentioned above is completely true; the error
'''index.js:1 Warning: Cannot update a component (Inscriptions) while rendering a different component (PaySummary). To locate the bad setState() call inside PaySummary, follow the stack trace as described in ...''''
Has to do with the fact that the API call is Asynchronous and when you rapidly change the pages, the set state call (for updating the data returned from the API call I assume) is still waiting to be called after the data is returned from the API. So, you have to always clean up your Async functions in useEffect to avoid this error.

react custom hooks vs normal functions, what is the difference

I'm trying to wrap my head around custom hooks. I understand normal hooks which is just fine, but my question is, when writing a custom hook, what is the difference between that and a normal function? I mean why not call it a normal function instead of calling it something like use*
I believe no one has answered your question exactly. I'm still also understanding the benefits and purpose of having this extra feature called hooks, but I can still share my understanding.
React Hooks are JS functions with the power of react, it means that you can add some logic that you could also add into a normal JS function, but also you will be able to use the native hooks like useState, useEffect, etc, to power up that logic, to add it state, or add it side effects, memoization or more.
So I believe hooks are a really good thing to manage the logic of the components in a isolated way.
So, you could have a foo.component.js (UI), a useFoo.js(logic), where useFoo will contain maybe many js functions and one hook to manage that functions and return what it's supposed.
This is an amazing video about react hooks, fully recommended
https://youtu.be/J-g9ZJha8FE
There are some differences and problems that make us use react custom hooks:
First of all, if you use normal functions, with every re-render of the component, this function will be created again and it causes the lack of performance. you may think that it can be fixed by using useCallBack and make react not to create a new function every time it re-renders but it is not the main problem that we are going to solve.
The main problem as the react document has discussed with a brief example of tracking online friends, is avoiding copy-pasting the same logic in different functional components which they need to be stateful too.
If we use normal functions inside a component and use useCallBack to avoid creating a new function every time, we did not solve the problem because in every component we should also copy this logic so this did not solve the problem.
The other solution is to make a function outside the functional component to handle this logic, but there is a big problem: in a normal function outside of the component, we don't have access to states because as we mentioned, this implemented logic is stateful and we have access to states only in react components.
So what is the solution here? yes, Custom React Hooks!
It is a stateful function that uses other react built-in hooks (e.g. useState, useCallback etc.) that can wrap around the stateful logic that you wanted to gather in one place and avoid copy and pasting the same logic in multiple components.
With this approach, you can put your logic outside of the component in another function while you are getting the benefit of stateful functionalities of react.
I hope that this answer may solve your problem and resolve your ambiguity.
From the React docs:
A custom Hook is a JavaScript function whose name starts with ”use” and that may call other Hooks. [...] Its name should always start with "use" so that you can tell at a glance that the rules of Hooks apply to it.
So why define custom Hooks with a special "use" naming prefix?
1.) It tells consumers, that these functions are intended to be used with React and obey to an implicit contract (above mentioned rules).
2.) You can have tooling support which checks and enforces these rules. For example, eslint-plugin-react-hooks utilizes a heuristic that assumes, a function starting with "use" prefix and a capital letter after it is a Hook.
React Hooks (custom or non-custom) should start with the use prefix. As well as, as per the React Documentation:
1) Hooks should be called from the React code only not from the Regular JS functions. Hence, Hooks' scope is limited to the React code world and has more power to do a lot with React code. Rather than JS, regular functions could be used across application but as react code guidelines keep the code more aligned to react syntax.
2) In the class-based components, the Hooks won't work but regular functions will.
3) In the regular JS functions, you can't access useState, useEffect, useContext etc. but in react custom hooks I can.
A custom hook depends on one more other hooks. By design React hooks are meant to be used from a component's render method. You will get a warning if you try to use a hook anywhere else. Custom hooks follow the same convention as built-in hooks because they have to be used in the same fashion. The use prefix is just a convention to identify hook functions which are usually call at the very top of a component render method.
You can name your hook function anything you want but as I mentioned, you will get a warning from React if used outside of a render method.
You can call it whatever and it will still work fine. The only advantage is that if you use the “useName” convention, React will check for error whether it correctly follows the rules of hooks. It just makes your task slightly easier.
As other users have stated custom hooks or hooks, in general, are used where we have to do anything related to react component while other util functions are not tied to react state and won't work is areas where react state logic is in place.
An example of custom hooks be useCustomNavigation which could a list of navigator function like navigateToHome, navigateToCheckout etc. So when you to route to homepage from different parts of code, we just use this hook. Also any logic/feature like analytics, and side effects could be part of navigateToHome function.
An example of Util function could be anything like capitalize which does not has to do anything with react or react component. You cannot create a util function called navigator and add useNavigation.
As I see it, custom hooks have their own specific purpose and have their own characteristics and approach.
What I mean is that in certain cases we would want to create a custom hook and not a function.
For example, if you have a need to store some data in the Localstorage you would want to create a custom hook for that and call it "useLocalStorage" and if you want to create a component, let's say a page form, you would want to write a function component.
Difference being that our hook is not a component and shows nothing on our UI.
It is simply a logical operation.
The reason I see them as different other than the "logical" example above is that our custom hooks are unique in a way of allowing the usage of other custom hook related hooks. For example, the "useDebugValue" which can only work in a custom hook.
What is weird to me is the way React differentiates a function from a custom hook, which I think is the main cause of the confusion.
It "checks" your function name and if it starts with "use" then it's a custom hook. What I think would have been a better option is to change the "const" declaration to a "hook" declaration or give it a unique type.
TL;DR, custom hooks are the logic and will allow the usage of hooks like "useDebugValue" and our functions are mostly UI related.

Why use useState over this.state?

I have been learning React hooks lately and I am currently facing useState. I know this is a way to use state in functional components but I wonder what the real benefits are above using a React.PureComponent with this.state?
Is it really bad practice now to use a PureComponent instead of useState or useEffect? Does this make the app "faster"?
I know this question sounds dumb because useState is the new kid on the block but I just need a valid reason to refactor my old components into this new pattern?
Edit: I've been using hooks for a while now and like them a lot (changed my opinion), however it increases the learning curve and there are pitfalls:
Good stuff:
Not wrapping your component in Higher Order Components (looks cleaner and sometimes order of HOCs can cause issues)
Composability and re-use becomes easy - splitting code out to custom hooks is second nature. Also reduces argument for adding other abstraction concepts around state management, data fetching, utilities since hooks can do it all.
No confusion around this (easily avoided with arrow functions in classes tbh)
Some components come out cleaner and terser (but some especially with lots of event listeners can turn into a hot mess without careful architecture and knowledge of how to make the best use of hooks)
Some libraries are hook compatible or hook focused only these days (not a "good" thing but an argument for use)
Bad stuff:
Larger API surface area/knowledge - memo, useCallback, useMemo, useRef, useEffect, useLayoutEffect, useState etc. Ask a beginner how to debounce a callback - suddenly it's a hard problem.
Functions can become unmanageable since hooks have to all be called in them in the same order (note: you can make your own hook with more hooks inside to split things up)
Trading confusion around this for much more problems such as:
Infinite loops when you both read and write to a variable in a memoized hook
Stale data if you didn't list dependencies, also if you didn't then you can prevent garbage collection on any trapped references.
Getting into a dependency hell to avoid stale references (wrapping stuff in useCallback, then "tunnelling" some of the variables in with useRef etc)
Performance degradation since hooks are slower to execute and create, non-hook functions are created every render and also will break purity checks of children, even functions in hooks such as useRef (and I believe useCallback) are quietly created and discarded every render in favour of the first one created.
Testing hooks nested in a function is harder/more complex than testing class methods
Side note: Solid framework has a better implementation of hooks which don't require dependencies
TL&DR: There is no need to refactor all old components.
useState and others react hooks introduce a new way to implement your components. They can be helpful as they simplify code reusability. You can move your specific logic to a custom hook and use it in several components. Custom hooks can call useState and they don't have any possibility to damage state from other useState calls. It allows you to split component logic more wisely.
So there are 2 main profits of using useState: code reusability and code splitting.
When it's better to refactor old components?
Let's say, you have 3-4 legacy components, which make similar things, but it's complicated to reuse code. You can rewrite such components to hooks, move all common logic to custom hook and reuse this hook in all of these components.
Also, if you have any additional questions you can take a look to this https://reactjs.org/docs/hooks-intro.html article
And one important thing: PureComponent equivalent in "functional component world" is to wrap your function with React.memo
useState, this.state and PureComponent are different terms and need not be confused together. As you understand useState is a way of handling state in a functional component whereas you use this.state for a class component.
As far as PureComponent is concerned, it used to optimize renders and you can use React.memo for the same purpose for a functional component.
Also as far as refactoring is concerned, there is no need to do that since Class components will continue to exist and react community recommends you to not refactor the previous code.
I recommend for you to watch React Today and Tomorrow and 90% Cleaner React With Hooks
also, you can read Introducing Hooks
according to using pureComponent, pureComponent is similar to Component which is Class, check classes confuse both people and machines section to understand why functions are better than classes.

Is it better to pass context to a custom hook or call useContext inside the custom hook?

I have a growing number of custom hooks and many of them access the same react context via the useContext hook. In many components there is the need to use more than one of these custom hooks.
Is it better to call useContext once per component and pass the context into my custom hooks or is it better to call useContext within each custom hook? There may not be a right or wrong answer, but by "better" I mean is there a best practice? Does one approach make more sense than the other?
I would suggest passing the context in, personally: I believe that will make the custom hook more clear, more flexible and more testable. It decouples the logic that operates on the context data from the logic responsible for getting that data.
Clarity
If you use useContext inside a custom hook, that becomes an implicit contract for the hook: it's not clear from looking at the call signature that it depends on values from context. Explicit data flow is better than implicit data flow, generally. (Of course, the Context API exists because sometimes implicit data flow is useful, but in most cases I think it's better to be explicit)
Flexibility
You might at some point find a component that needs to leverage the logic contained in the custom hook, but needs to provide a different value than the one on the context, or perhaps wants to modify the value. In this case, it'd be very convenient to do this:
const MySpecialCaseComponent = () => {
const context = useContext(MyContext);
useMyCustomHook({
...context,
propToOverride: someValue
});
return (<div></div>)
}
That's highly inconvenient if the custom hook reads straight from context - you'd probably have to introduce a new component, wrapped in a new context provider.
Testability
It's easier to test a custom hook if it doesn't depend on context API. Perhaps in the simplest cases, you can just call your custom hook with test data and check the return value.
Or you can write a test like:
test("Test my custom hook", () => {
const TestComponent = () => {
useMyCustomHook({ /** test data */ });
return (/* ... */);
};
const element = shallow(<TestComponent />);
// do testing here
})
If you use context in your hook, then you'd have to render your test component inside a <MyContext> provider, and that makes things more complicated. Especially if you're trying to do shallow render (and even more so if you're using react-test-renderer/shallow, testing components with context is more complicated.
TL;DR I don't think it's wrong to useContext inside a custom hook, but I think explicit data flow should be your first resort, for all the usual reasons that explicit data flow is generally preferred over implicit data flow.

Resources