How to use states inside helper function in React? - reactjs

I have simple helper function for API calls, like below
const API_GET = async (params) =>
fetch(params)
then();
And i need to use few states inside of this functional component states are provided by useContext hook and its separate file, as global state manager, since useStates hook can not be called outside of function and useEffect hook, How can i access those states inside the helper function. Plan is to create global notofication & loader handler using hooks.
Thanks.

You can create a custom hooks where you'll have access to hooks. Something like
const useFetch = params => {
const [result, setResult] = useState();
useEffect(() => {
doFetch = async () => {
const res = await fetch(params);
setResult(res)
}
doFetch();
}, [params])
return result;
}
You can use all your needed hook inside a Custom hook.
In this exemple, be ware that as params is set as dependendy array of useEffect, any change in params will re-trigger the api call

Related

React's new use() hook falls into infinite loop

I'm trying to load data for a client component. I can't use await/async as specified by React's RFC about use() hook. Thus I need to use use() hook.
However, it goes into infinite loop.
Here's my code:
import { use } from 'react'
const Component = () => {
const response = use(fetch('some_url'))
const data = use(response.json())
return <div>{data}</div>
}
Based on my intuition, I tried to use a callback inside the use() hook, as we do for useEffect():
const response = use(() => fetch('use_url'), [])
But it complained that an invalid parameter is passed into the use() hook.
I can't find anyting online. What should I do? What have I done wrong?
You need to "stabilize" the return of fetch. You could memoize it
const Component = () => {
const fetchPromise = React.useMemo(() => fetch('some_url').then(r => r.json()), [])
const data = use(fetchPromise);
return <div>{data}</div>;
}
I guess you just wanna memorized use result.
const response = useMemo(() => use(use(fetch('some_url')).json()), ['some_deps'])

Why "React hook is called in a function" while exporting simple single function that accesses a useAtom state?

I have this simple function that needs to set a state from jotai. I would like this function to have it's own seperate file or be cleaned up somewhere, since it will be reused. I'm new to React and come from Angular. It's kind of a function in a service Angular wise.
How would you solve this properly in React?
Code:
export const setMetamaskWallet = (): void => {
const [, setWeb3] = useAtom(web3Atom);
const [, setLoading] = useAtom(loadingAtom);
const [wallet, setWallet] = useAtom(walletAtom);
setWeb3(
new Web3(window.ethereum),
)
//Todo: Create check if metamask is in browser, otherwise throw error
const setAccount = async () => {
setLoading(true);
const accounts = await window.ethereum.request(
{
method: 'eth_requestAccounts'
},
);
setWallet(
accounts[0],
);
setLoading(false);
}
if (!wallet) {
setAccount();
}
}
Hooks can only be called in React functional components or other hooks. Here it appears you have called it in a typical function, hence the error. You could package this functionality in a custom hook. It may however be most appropriate to keep this function as it is, and instead of calling hooks within it, pass the relevant data into the function as parameters.

React Hook - useCustomHook to set outside useState and useRef

I have the main component along with local state using useState and useRef, I also another custom hook, inside the custom hook I would like to reset my main component's state and ref, am I doing correctly by below?
// custom hook
const useLoadData = ({startLoad, setStartLoad, setLoadCompleted, setUserNameRef}) => {
useEffect(() => {
const fetchUser = async() => { await fetchFromApi(...); return userName;};
if (startLoad) {
const newUserName = fetchUser();
setStartLoad(false);
setLoadCompleted(true);
setUserNameRef(newUserName);
}
}, [startLoad]);
}
// main component
const myMainComp = () {
const [startLoad, setStartLoad] = useState(false);
const [loadCompleted, setLoadCompleted] = useState(false);
const userNameRef = useRef("");
const setUserNameRef = (username) => { this.userNameRef.current = username; }
useLoadData(startLoad, setStartLoad, setLoadCompleted, setUserNameRef);
refreshPage = (userId) => {
setStartLoad(true);
}
}
Am I using the custom hook correctly like by passing all external state value and setState method in? Also I found even I don't use useEffect in my customHook, it also works as expected, so do I need to use useEffect in my custom hook? Any review and suggestion is welcome!
First, I think isn't a good approach you use component methods inside custom hook (like "set" methods provided by useState). You are binding the hook with the main component's internal logic. If the purpose of custom hook is fetch data from API, it need to provide to main component the vars that can be able the main component to manipulate its state by itself (like return isFetching, error, data, etc. and don't call any main component set method inside hook).

How to use Async / Await with React hooks?

I am learning React and following a video tutorial. The instructor used class components and I'm using functional components to brush up on hooks concept.
I want to convert this code into a functional one:
return(
<div className={classes.editorContainer}>
<ReactQuill
value={this.state.text}
onChange={this.updateBody}>
</ReactQuill>
</div>
);
}
updateBody = async (val) => {
await this.setState({ text: val });
this.update();
};
I have tried to do this but async doesn't seem to work as I expected. Await is not working for setText.
const [text, setText] = useState('')
const updateBody = async(val) => {
await setText(val)
update()
}
First of all, setText function does not return a promise that you can await and make sure the data is set.
If you want to set the state and make sure you are calling the update function after the value is set, you need to use another hook called useEffect.
By using useEffect you can basically get the latest state when it is updated.
If you don't care about whether the state is set or not you can convert your async function to the following,
const updateBody = (val) => {
setTitle(val)
update()
}
You can use useEffect hook to trigger a function which you want to get triggered after the state has been updated.
const [text, setText] = useState('')
useEffect(() => {
update()
}, [text]); // This useEffect hook will only trigger whenever 'text' state changes
const updateBody = (val) => {
setText(val)
}
Basically you useEffect() hook accepts two arguments useEffect(callback, [dependencies]);
callback is the callback function containing side-effect logic. useEffect() executes the callback function after React has committed the changes to the screen.
Dependencies is an optional array of dependencies. useEffect() executes callback only if the dependencies have changed between renderings.
Put your side-effect logic into the callback function, then use the dependencies argument to control when you want the side-effect to run
you can find more info about useEffect() hook in this article

Custom hooks not working properly with useEffect

I wasn't sure on a title for this issue, but I can better explain it here. I have a custom hook that is relying on some information. Part of the information must rely on an async call.
I have three situations happening.
Tried conditionally rendering the custom hook, but react does not like that due to rendering more hooks on a different render.
The custom hook is only mounting once and not passing in the updated information it needs.
I tried passing the dependency to the custom hook and it causes an infinite loop.
Here is a small example of what I'm doing.
Custom Hook:
export function useProducts(options){
const [products, setProducts] = useContext(MyContext)
useEffect(() => {
// only gets called once with `options.asyncValue` === null
// needs to be recalled once the new value is passed in
const loadProducts = async () => {
const data = await asyncProductReq(options)
setProducts(data)
}
loadProducts()
}, []) // if I pass options here it causes the infinite loop
return [products, setProducts]
}
Inside function calling:
export function(props){
const [asyncValue, setValue] = useState(null)
useEffect(() => {
const loadValue = async () => {
const data = await asyncFunc()
setValue(data)
}
loadValue()
}, []}
const options = {...staticValues, asyncValue}
const [products] = useProducts(options)
return (
<h2>Hello</h2>
)
}
I know that I need to pass the options to be a dependency, but I can't figure out why it's causing an infinite reload if the object isn't changing once the async call has been made inside the func.
You were correct in adding options in the dependencies list for your custom hook.
The reason it is infinitely looping is because options IS constantly changing.
The problem is you need to take it one step further in the implementation and make use of the useMemo hook so options only changes when the async value changes, instead of the whole component changing.
So do this:
const options = React.useMemo(() => ({...staticValues, asyncValue}), [asyncValue])

Resources