How do to pass parameter to a custom hook - reactjs

How do I pass a parameter from my return statement to the custom hook, I have created everything but just the method to pass the parameter to the custom hook is my problem.
const {
geodata: address,
isPending,
geoerror,}
= useGeo(latitude, longitude);
You see useGeo that's the custom hook where I want to pass latitude and longitude (This works but I don't know to pass the parameter from the return statement)
So I tried method like this:
const getAddApi = (latitude, longitude) => useGeo(latitude, longitude);
and in the return statement I tried this below but it didnt work I keep getting Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
<Text>{getAddApi(item.latitude, item.longitude).geodata}</Text>

Custom hook is follows:
a function
call at least one build-in hook inside
used inside a function component (this is your error)
Suppose I design a custom hook like this,
const useGeo = (latitude) => {
const [state] = useState(latitude)
return state
}
It's a simple function with input latitude and return state. Now you can use it in a function component.
const Title = () => {
const s = useGeo(273)
...
}
This is what a custom hook about. It's used mainly for algorithm refactoring. If you want to know more about input and output, just ask what you normally do for a function. The rest is the definition of the hooks that you have to meet which i listed above.

Related

Is there a way to modify a value when its changed after rendering without useEffect

I have a react app that fetches the data that I need on render.
When the data arrives, I have a useEffect in place that will format the data and update the variable required.
My issue now is that the format function that we are using has been changed to a hook, which I can't use in the useEffect anymore, and I was wondering if there was a way to basically replicate the process without the useEffect
For a simplified example, originally I had something similar to this component:
const MyComponent = ({myValue}) => {
const [outputVal, setOutputVal] = useState(0);
useEffect(() => {
if (myValue != null) setOutputVal(formatCurrency(myValue));
}, [myValue]);
[...]
formatCurrency was a simple function using the Intl.NumberFormat functionality, and would just convert the value as needed. I've now swapped to using the react-i18next library, which has other functionality that I want, but it uses hooks, which means I can't use the function within the useEffect.
I've tried to change it to use the function when the page loads, ie:
const [outputVal, setOutputVal] = useState(formatCurrency(myValue));
The issue that I've found though is that the initial value of myValue is null, and the function doesn't rerun when myValue is updated.
Any help or info on this would be great.
Since formatCurrency probably just formats the numerical value into a string, you could just run it on every render and treat it like any ordinary variable you'd use during rendering, i.e.:
const MyComponent = ({myValue}) => {
const outputVal = formatCurrency(myValue);
return <p>{outputVal}</p>
};

Modifying state in react-query's query function

I have written a wrapper around fetch that lets me handle error states from my API like a 401. When it gets an error, the custom fetch function sets some state using react hooks.
Because I use hooks in the function, I cannot just import it normally. Therefore, I pass this wrapped function around using context.
When I use react-query, I would like to just use this wrapped function in the following way:
function myQuery(key, apiFetch) {
return apiFetch(...)
}
function MyComponent() {
useQuery('key', myQuery)
}
In this example, apiFetch is an available argument in the query function.
One option I do have here is to just inline the function like so:
function myQuery(key, apiFetch) {
return apiFetch(...)
}
function MyComponent() {
const apiFetch = useApiFetch();
useQuery('key', (key) => apiFetch(...))
}
However I find this a little messy and would like to keep the query/mutation functions separate if possible.
Does anyone know of an approach I can take to have my apiFetch function be available to me in react-query's functions?
If you don't want to repeat calling useApiFetch and useQuery hooks in multiple components, you can extract both hooks into another custom hook that integrates react-query with your fetch hook:
function useApiQuery(param) {
const apiFetch = useApiFetch();
return useQuery(['key', param], (key) => apiFetch(...))
}
Then use it in your component:
function MyComponent({ param }) {
const { data, error } = useApiQuery(param);
return (...);
}

state inside custom hook and the main component

Let's say I have a custom hook for calling some API and I have a loading state defined inside this custom hook.
I consume this in my main component. Now my question is can I treat the useState that I did inside the custom hook to be exactly the same, as it would have been added in my main component.
e.g. can I use this "loading" state (both getter & setter) in my main component also for say some other purpose e.g. if i have API calls using some other way as well e.g. using axios?
Thus to summarize, for mental model perspective, can I treat a state variable defined inside the custom hook as exactly the same as one in the component itself?
You can.
If you return both getters and setters, you can use it as if it was a normal "root" useState call.
A custom Hook is a JavaScript function whose name starts with ”use” and that may call other Hooks. (https://reactjs.org/docs/hooks-custom.html#extracting-a-custom-hook)
Example:
const usePageLoading = () => {
const [pageLoading, setPageLoading] = useState(true);
return { pageLoading, setPageLoading };
};
const MyComponent = () => {
const { pageLoading, setPageLoading } = usePageLoading();
// ...
};

How to store values of a function type (e.g. arrow functions) with the React Hook useState?

In Javascript and Typescript, (arrow) functions are supposed to be first class citizens. Hence, I expect that I can have function types in my React state. However, the React Hook useState does not seem to play nicely with function types.
I have the following code:
import React, { useState } from "react";
function callApi(num: number): number {
console.log(`Api called with number ${num}. This should never happen.`);
return num;
}
type Command = () => number;
function Foo() {
const [command, setCommand] = useState<Command>();
console.log(`command is ${command}.`);
// ####################
const handleButtonClick = () => {
console.log("Button clicked.");
const myCommand = () => callApi(42);
setCommand(myCommand);
};
// ####################
return (
<div>
<button onClick={handleButtonClick}>Change state</button>
</div>
);
}
export default Foo;
in this Codesandbox
When I visit the page and click the button, I get the following console output:
command is undefined.
Button clicked.
Api called with number 42. This should never happen.
command is 42.
Hence, one can see that although in my button handler the state variable command should be set to a new arrow function, React does not do that. Instead, it executes the new arrow function and stores the result in the state variable.
Why is that and how can I store functions in React state without having to use some inconvenient wrapper object?
For context: Quite often it would be convenient to build certain command functions by means of various user inputs and store them in state for later use, e.g. when building a job queue.
Why is that and how can I store functions in React state without having to use some inconvenient wrapper object?
Why?
React's useState takes in either a function (that it'll use as callback that gets the current value of the state) or a value, so if you pass () => callApi(42) it will understand it like you want the new State to be the return value of callApi when passing in a 42.
What can you do?
If you really need to do that this way (storing a function in the state), you can do something like useCommand(() => myCommand).
However, I would suggest you don't store functions in your component's state.
If you need a new instance of a function (or a new function) when something in your code has changed, use useCallback or useMemo instead.
Either will create a new function whenever one of the values specified in the dependencies array is changed.
useCallback will create a new function when their dependencies changed, so you can use it like:
function Button() {
const [buttonAction, setButtonAction] = useState(null);
// dynamicHandler will be a new function every time buttonAction changes
const dynamicHandler = useCallback(() => {
// Logic here based on the buttonAction value
}, [buttonAction]);
const handleClick = () => {
setButtonAction(BUTTON_ACTIONS.DO_SOMETHING);
};
return (
<button onClick={handleClick} />
);
}
Check out the useCallback documentation.
You can store function as object
setCommand({ function:()=>callApi(42) })
Then when you want to call the function stored in state, you can simply do command.function()

Changing the function to a reusable hook in React.js in functional component

How can I transform the below function checkStatus to a reusable hook in React? I am returning the boolean value in the render component.
const someComponentChecker = (props) => {
const { isEnabled, isTrueMode, datasItems } = props
function checkStatus = (data, isEnabled) => {
if(isTrueMode && !isEnabled){
return !data.isUpdate
}else if(!isEnabled){
return !data.isCreate
}else{
return true
}
}
return (
datasItems && datasItems.map((data, index) => {
return <SampleComponent
enabled={checkStatus(data, isEnabled)}
/>
})
)
}
A custom Hook is a JavaScript function whose name starts with ”use” and that may call other Hooks.
Unlike a React component, a custom Hook doesn’t need to have a specific signature. We can decide what it takes as arguments, and what, if anything, it should return. In other words, it’s just like a normal function. Its name should always start with use so that you can tell at a glance that the rules of Hooks apply to it.
If you feel that your function fulfills these criteria you can simply extract the code and create a new file with prefix 'use'.
But for your 'checkStatus' it doesn't seem like you are using any hook inside that. And its a very simple function. may be you can just make a util function and use it wherever you want.

Resources