It seems to me that one could replace useEffect/componentDidMount with a state hook and function components. For example, if I wanted to make a fetch in useEffect or componentDidMount, I could simply create a function component that rendered the component that needed fetching, add the fetching method in the function (which will execute upon rendering) which modifies a state hook (so that once the data arrives, the page will re-render with the data). Since React has selective rendering, any other part of the function component that gets updated won't cause an unnecessary fetch.
Am I correct in saying this? Are there any other specific instances where useEffect/componentDidMount is strictly better?
Am not sure why you want to replace componentDidMount in class component or useEffect with a custom function for the use case you highlighted but those two are different in terms of behavior, componentDidMount is one functionality that useEffect provides in function component. useEffect is a combination of componentDidMount and componentWillUnmount and you can have mulitple useEffect on one function component. useEffect accept array of values that could make it run again, all you do is specify those value for that particular useCase you wanted and whenever that values changes the useEffect is called, for UI changes you attach your useState to your logic and if followed accordingly you wont get unnecessary fetch request, if you want useEffect to be called just once then attach just an empty array like this useEffect(()=>{//your fetch logic here },[])
Related
I have the following queries -
What's the difference between useEffect, useMemo and useCallback hooks ? I have gone through many examples and explanations but still am not clear on their difference. All I know is that each executes only when at least one of their dependencies change.
If useRef hook allows us to persist with values between re-renders, why not use a simple variable (not a state) for the same ? I read somewhere that if not changed manually, useRef will have the same value all the time. Can't we achieve this with a simple variable ?
tl;dr
useMemo fired immediately, useCallback not.
local variables a not persisted between renders
Explained
useMemo and useCallback area really very same. The difference between them are mentioned in the hooks names.
useMemo is created for calculating some heavy things (like taking some very long list and mapping it in another) and storing it for some time – as documentation says React can drop useMemo result and make hook to run again. When component is rendering first time, all useMemos continuously runs calculations and their results may be used during the render. When rendering next times (if no hook dependencies changed) React do not call passed function but just using memorized result.
useCallback is created just for preserving variable references to functions that is passed as first argument. It is very helpful when callback, created with that hook is passed to some children components cause persistent variable reference do not invalidates memorized components.
Small example:
const app = () => {
console.log('app render starts')
const title = React.useMemo(() => {
console.log('running calcualtion!')
return 'Hello world'
}, [])
console.log('app render continues')
const handleClick = React.useCallback(() => {
console.log('handling click')
}, [])
console.log('app render continues again')
return <div onClick={handleClick}>{title}</div>
}
/*
Output after mounting app:
- app render starts
- running calcualtion!
- app render continues
- app render continues again
And after clicking div:
- handling click
*/
About useRef
React functional components are functions that runs again on every component render. Without hooks that functions are totally pure and unable to contain any state or preserve variables value – all function-scoped variables are created on every render again.
Hooks know which component are currently being rendered, so hooks able to store some data about component and get it back when component re-rendered.
In lot of cases useRef really are just a way to persist value between renders. As described above, you can't achieve that with simple variables inside of component's function. It could be achieved with some global variable declared outside of component. It even may be better choice if variable value do not depends one component mount/unmount which are handled by useRef.
I'm working with redux saga and redux toolkit. In the EachUser component, I don't understand why the component is mounting over and over again if I don't use the useEffect hook. Could someone help me understand why it is.
I'm not changing any props or state so I don't think infinite loop should happen but it is happening.
Here is the link to my code sandbox: Redux Saga With Redux toolkit
Happens following:
When you are trying to dispatch your FETCH_SINGLE_USER action on the top level of your functional component it will be executed on each render cycle (your function is re-rendered(executed) each time when props or state changed, also it will be re-rendered when the parent component is re-rendered (if you don't use React.memo).
So when you are dispatching your action on the top level of your functional component it will
fetch user from the server
->
update your store
->
updated store will cause re-render of the component as you are selecting updated state with useSelector
->
fetch user from the server action dispatched again (we are inside of the infinite loop)
So why we need useEffect - it is the hook that helps us to make some actions on special conditions. In the second parameter, you should put an array of dependencies, once dependency changed it will cause hook rerun. If the array is empty - hook will be executed only once when your functional component mounted. Also you can return cleanup function that will be executed, once your component unmounted. More documentation on useEffect hook here
try to remove dispatch from the array of dependencies
useEffect(() => {
dispatch({ type: sagaActions.FETCH_SINGLE_USER, userId });
}, [userId]);
calling a function inside useEffect and specifying it in an array of dependencies can cause an infinite rerender
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.
I am using a custom hook without a state and want to "persist" the hook.
The hook is called useMessage() and should only be rebuilt in the first render cycle since i don't use any state in there.
I want to have a global hook the redux hook useDispatch().
How is that possible?
EDIT:
I just want to have 1 reference / a singelton of my hook to not get rerendered all the time!
Is there any way to memorize the hook? My goal is that i am able to add the hook in dependencies of e.g. useEffect() and this never will cause a rerun of the useEffect(). Just like useDispatch / useRef / ...
I'm not sure if this is what you mean - but try this:
const [myValue] = useState(() => myInitialValue);
useState accepts a callback function as a parameter, which will only be executed on first render for your component. For all future renders, it will return the first value that was returned from your function.
Well the answer is - you just can't. A custom hook will always rerun if the component where you included it runs again.
What I expected: Just return a memorized Value (useMemo) containing the dependencies in the array. This will keep the custom hook simple and only a small part will rerun.
I'm just new to React Hooks, and playaround with it.
Just wondering if there any solutions that I could use useEffect to fetch data several times after componentDidMount.
Normally we use useEffect to fetch data based on some props change by passing them.
useEffect(()=> {
fetchApisomefunction()=>{}
},
[]); // normally do this for componentDidMount
How can I fetch data again after that?
UPDATE
callback function could solve this.
Assuming that you are not using Redux or Context API,
so component A and B are not communicating to each other directly.
On the other hand, there will be a parent component which joins those two components.
As you've said, component B will post the data, and that should change parent's state.
Since react child component is being re-rendered whenever its parent component's state or props change, component A will also be re-rendered.
So all you have to do is to use useEffect without second parameter [].
Actually it is not the question of using Hooks, but the question of react component structure.
Keep in mind that the two child components should not directly communicate to each other.