I'm building a ReactJS based website. I'm using hooks if it makes a difference.
I'm writing some security code for anti forgery token etc. I would like to call a function automatically without implementing it page by page.
How to call a function from all components' componentDidMount? Is there a global event for it?
Right now doing this like this; but it is really complicated to follow all and implement this...
componentDidMount() {
token.Get();
}
If you are using Hooks, you are using function components, and therefore do not have access to lifecycle methods like componentDidMount. To trigger an effect on mount and unmount, you would have to do something like
React.useEffect(() => token.Get(), [])
(https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects)
To define a global behaviour as you seem to want, you may be able to implement the behaviour at the root App.js level. You could also possibly create a higher order component to wrap every component that needs this behaviour, but it seems overkill for one line of code (https://reactjs.org/docs/higher-order-components.html)
If you want to automatically add a token to all your requests, it's easy to do so with axios like this:
axios.defaults.headers.common['Authorization'] = YOUR_TOKEN;
See axios documentation for details.
Related
I have the following problem. I have a component which needs to call an API when mounted. I do the call in a useCallback like this:
const sendCode = useCallback(() => {
console.log('InsideSendCode');
}, []);
And then I call this function inside of a useEffect like this:
useEffect(() => {
sendCode();
}, [sendCode]);
The thing is that, even by using the useCallback, the message is displayed in the console twice and I've seen that this would be the only option.
I know about the StrictMode, but I don't want to disable it.
If everyone would have an opinion, would be great.
Thanks.
That is standard behavior in Strict mode:
When Strict Mode is on, React mounts components twice (in development only!) to stress-test your Effects.
Initially react was only calling render twice to detect if you have some side effects, but afterwards they also added calling effects twice during initial mount, to make sure you have implemented cleanup functions well. This only applies to strict mode AFAIK.
I suggest you read the link above. You have few options:
if the API call you are making is GET request which simply gets some information, let it be called twice, there is no much harm.
You could use a ref to keep track if it is first mount or not, and then correspondingly make request in useEffect only if this is first mount. Although this approach is not listed in official recommendations, I suppose you can use it as a last resort; it was documented at some point. Dan Abramov also mentioned you could use it as last measure, just they don't encourage it.
disable Strict mode
My app has a userService that exposes a useUserService hook with API functions such as getUser, getUsers, etc. I use a Hook for this because the API calls require information from my Session state, which is provided by a React Context Provider.
Providing the getUsers functions to a useEffect call makes the react-hooks/exhaustive-deps eslint rule unhappy, because it wants the getUsers function listed as a dep - however, listing it as a dep causes the effect to run in an infinite loop, because each time the component is re-rendered, it re-runs the useUserService hook, which recreates the getUsers function.
This can be remedied by wrapping the functions in useCallback, but then the useCallback dependency array runs into a similar lint rule. I figure I must be doing something wrong here, because I can't imagine I'm supposed to wrap every single one of these functions in useCallback().
I've recreated the issue in Codesandbox.
1: Encounter eslint warning: https://codesandbox.io/s/usecallback-lint-part-1-76bcf?file=/src/useFetch.ts
2: Remedy eslint warning by sprinkling useCallback in, leading to another eslint warning: https://codesandbox.io/s/usecallback-lint-part-2-uwhhf?file=/src/App.js
3: Remedy that eslint rule by going deeper: https://codesandbox.io/s/usecallback-lint-part-3-6wfwj?file=/src/apiService.ts
Everything works completely fine if I just ignore the lint warning... but should I?
If you want to keep the exact API and constraints you've already chosen, that is the canonical solution — you need to ensure that everything "all the way down" has useCallback or useMemo around it.
So this is unfortunately correct:
I can't imagine I'm supposed to wrap every single one of these functions in useCallback()
There is a concrete practical reason for it. If something at the very bottom of the chain changes (in your example, it would be the "session state from React's context" you're referring to), you somehow need this change to propagate to the effects. Since otherwise they'd keep using stale context.
However, my general suggestion would be to try to avoid building APIs like this in the first place. In particular, building an API like useFetch that takes an arbitrary function as a callback, and then calling it in effect, poses all sorts of questions. Like what do you want to happen if that function closes over some state that changes? What if the consumer passes an inline function that's always "different"? If you only respected the initial function, would you be OK with the code being buggy when you're getting cond ? fn1 : fn2 as an argument?
So, generally speaking, I would strongly discourage building a helper like this, and instead rethink the API so that you don't need to inject a "way to fetch" into a data fetching function, and instead that data fetching function knows how to fetch by itself.
TLDR: a custom Hook taking a function that is then needed inside of an effect is often unnecessarily generic and leads to complications like this.
For a concrete example of how you could write this differently:
First, write down your API functions at top level. Not as Hooks — just plain top-level functions. Whatever they need (including "session context") should be in their arguments.
// api.js
export function fetchUser(session, userId) {
return axios(...)
}
Create Hooks to get any data they need from the Context.
function useSession() {
return useContext(Session)
}
Compose these things together.
function useFetch(callApi) {
const session = useSession()
useEffect(() => {
callApi(session).then(...)
// ...
}, [callApi, session])
}
And
import * as api from './api'
function MyComponent() {
const data = useFetch(api.fetchUser)
}
Here, api.fetchUser never "changes" so you don't have any useCallback at all.
Edit: I realized I skipped passing the arguments through, like userId. You could add an args array to useFetch that only takes serializable values, and use JSON.stringify(args) in your dependencies. You'd still have to disable the rule but crucially you're complying with the spirit of the rule — dependencies are specified. Which is pretty different from disabling it for functions, which leads to subtle bugs.
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.
I have a code in which an API call is made inside the render method in a react app, is it correct?
The API call is made from a function placed inside a const function which is placed in another file
render method is place for presenting various elements to user and these elements can be used to trigger an api-call for various purposes. For example - checking validity of text entered in input-element, sending form-data async-ly to server, etc.
And this is a nice practice to put the code into various modules or separate files for better management, etc. for ex. call is wrapped inside a function and placed in a different file. Webpack helps in filling all various modules in place.
So it is alright to put api calls in render and calling a function defined inside another file for the same.
It is not correct.
1) If the api call is waiting for the call to complete(await or promise resolve), Then it is essentially blocking render.
2) React might call render function many times[it may or not lead to DOM update], which means you will be making redundant api calls as many times.
It is ok to do so, if it is in response to an event.
So No, just put the api call in componentDidMount or ComponentDidUpdate or if you are using hook, add a useEffect.
Good Luck!
It really depends on the use case.
There is nothing wrong with doing so as long as you aren't calling it everytime it re-renders. I assume you are making the request upon triggering of certain events(such as onClick). If yes, it may be cleaner to encapsulate it within a method.
async doSomething = () => {
// do the rest
// make API request
await getRequest();
}
return <>
<button onClick={() => this.doSomething()}/>
</>;
If the request is to be made only once and when the component is initialised, you should make that request within the componentDidMount lifecycle hook. According to the documentation for componentDidMount,
componentDidMount() is invoked immediately after a component is
mounted (inserted into the tree). Initialization that requires DOM
nodes should go here. If you need to load data from a remote endpoint,
this is a good place to instantiate the network request.
Otherwise, calling it on render() will result in the API request to be triggered everytime there is a re-render.
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.