ReactJS functional component props issue inside useEffect in Hooks - reactjs

I'm using a functional component as a child with props from parent. In the props i have a value array in which i'm getting as empty([]) inside useEffect and after some time, the same is getting rendered in the UI. I'm using useEffect to call a function and set the state only once as below and i want it to be like that. Here value is the props and checkEmpty is the function i'm checking and setting the state, completed. Is there any way to invoke the function inside useEffect once the value array is filled. But i want the useEffect to be invoked only once and needs to change the state completed with out letting it to an infinite loop.
useEffect(() => {
checkEmpty(value)?setCompleted(false):setCompleted(true)
}, [])

You can pass the value as a dependency of useEffect, and the hook only run when the value is changed.
useEffect(() => {
checkEmpty(value) ? setCompleted(false) : setCompleted(true);
}, [value])

Related

How do I call useEffect when the trigger is in another component?

I am trying to fetch data in a functional React component using useEffect (since the function is asynchronous) and I compute and return the data in h2 tags that was fetched in this component. However, I want to fetch the data when in another component (App.js) I hit the enter key. I have an enter key handler which calls a useState which I believe should re-render the component but since the useEffect is in another component, I am not getting the calling of the useEffect as I intend. What is the best method to press the Enter key and have useEffect in another component run?
function handleKeyDown(event){
if(event.key === 'Enter'){
//this setHeadingText is a useState variable which should re-render in App.js
setHeadingText(name);
}
It sounds like your useEffect is specifying an empty dependency array (instructing to run only once):
useEffect(() => {
//fetch some data
}, []); // This empty array ensures it only runs 1 time
Have a look at this section in the docs: https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects
If your second component has access to your headingText state, try specifying your headingText as a dependency to the useEffect, and any changes to it should trigger your useEffect
useEffect(() => {
//fetch some data
}, [headingText]); // Only re-run the effect if headingText changes
Alternatively, remove the dependency array from your useEffect.
Note: this will cause the useEffect to run on every re-render
useEffect(() => {
//fetch some data
}); // run every time the component re-renders
Now that I have understood properly, I think this is the solution you wished for:
The headingText value that is being updated in your App.jsx component should be passed down to your Child component with the help of props. So use <Child headingText={headingText} /> while loading the Child component in your App.jsx.
Inside your Child component, receive the value like this function Child(props) or function Child({ headingText }) if you have more values to pass, prefer props.
Now you can easily access the changes in value made in your App component inside your Child component with the help of props.headingText or headingText respective to the way you defined your Child in point 2.
To re-render your Child component, you will now use the useEffect hook with its dependency set to headingText, like:
React.useEffect(() =>
{
// Code for refetching
}
, [headingText]); // or props.headingText if your Child component uses (props)
For example: CodeSandbox
Hope that helps you!
you can make a conditional rendering with the other component, so it get rendered only if you press Enter which would invoke an event:
//App.js
import {AnotherComponent} from './anothercomponent.js' //assuming the file is in src folder
function RenderOnEnter({pressed}){
if(pressed){
return (
<AnotherComponent/>
)
}
return null
}
function App(){
const [pressed,setPressed] = useState(false)
function handlePressed(e){
if(e.target.key === 'Enter'){
setPressed(True)
}
else{
setPressed(False)
}
}
return(
<div>
<button onClick={(e)=>handlePressed(e)}>Click me to obtain data!</button>
<RenderOnPress pressed={pressed}/>
</div>
)
}

Trigger some API once react state empty

I want to trigger An API to do some actions when the value in the react state be empty, Is there a way in react state hook to achieve that?
If you are using a functional component you can use the "useEffect" hook with a proper dependency.
Class base components you might choose (if I understand your situation properly) something like the "componentWillUnmount()" method.
You could have a useEffect hook with the state as a dependency, in-which you can check if the state is empty and act accordingly.
Example:
const [state, setState] = useState([]);
useEffect(() => {
if (state.length !== 0) {
return;
}
// Can make your API call here (preferably call a function that does it)
// and then set the state.
setState(...);
}, [state]);
useEffect is a hook that accepts a callback as the first argument, and a dependency array as the second.
The callback will execute upon re-render whenever any of the dependencies in the array change.
Note: this is relevant only for functional components, for class-based component we have the componentDidUpdate lifecycle hook.

Using redux data in the useEffect hooks

I am now trying to call an API using data from the redux store.
Let say I got 2 API calls, Api A and Api B Inside the parent component I already called the API A and save the data inside the redux already.
Now I am in another component. I need to call Api B. But API B has a params, which I will get from API A. So Inside the Second component, I am using useEffect hook to call the data.
To get the params from the redux, I am using useSelector Hook.
Inside the second component, UseEffect Hook is something like this:
useEffect(() => {
let splitText = cartList?.OrderDTO?.DeliveryCountry;
let deliveryAddressId = splitText?.split(',');
if (cartList.OrderDTO?.DeliveryCountry !== '') {
dispatch(getShippingMethodById(token.access_token, deliveryAddressId));
} else {
dispatch(
getShippingMethodById(
token.access_token,
cartList.OrderDTO?.CustomerAddressId,
),
}
}, []);
So in the useEffect hook, I got the deliveryAddressId from redux. To draw in data from the redux into component, I am using useSelector hook
let cartList = useSelector((state) => state.productReducer.cartList);
The problem is that I always get undefined for cartlist when ever I tried to access it inside the useEffect hook
So the dispatch called are always getting undefined. So What can I do to make this hooks works?
You should add cartList to your dependency array, so the useEffect hook watches for updates to that piece of state. As it is written now, the useEffect only runs on the first render, where cartList is probably undefined.
React - useEffect Docs
useEffect(() => {
let splitText = cartList?.OrderDTO?.DeliveryCountry;
let deliveryAddressId = splitText?.split(',');
if (cartList.OrderDTO?.DeliveryCountry !== '') {
dispatch(getShippingMethodById(token.access_token, deliveryAddressId));
} else {
dispatch(
getShippingMethodById(
token.access_token,
cartList.OrderDTO?.CustomerAddressId,
),
}
}, [cartList]); // Add 'cartList' to your dependency array here
Solution is that you add cartList inside the dependency array.
useEffect(() => {
// All your logic inside
}, [cartList]);
I don't have info about the complete parent-child component structure, but from what I understood with the error I can explain the issue.
You are using [], for useEffect dependency, which means the callback inside useEffect will be triggered only once when the component mounts.
It is possible that when your component mounted, the API call in the parent was not complete, and you have still have undefined in store for cartList.
To check this hypothesis you can add console.log in API response and
inside the useEffect.
What else you can do?
You can not render the child component until you have data from the API call.
Why adding cartList in the dependency array fixed the issue?
By dependency array inside useEffect, your useEffect call back will be
called whenever the values in the dependency array change + on the
mount.
So, at the time of mount of the child component, useEffect's callback will trigger (cartList as undefined), then when the API call is successful and after that data is pushed in state, your child component will rerender and will retrigger the callback inside useEffect with the actual(which you got from API and pushed in store) cartList data.

react.js hook (too many re-renders)

I'm new to react.js hook. Not sure about why the following code doesn't work.
import React,{useEffect,useState} from "react"
function App() {
const [fruit,setFruit] = useState("orange");
setFruit("apple")
return (
<div>
<h1>{fruit}</h1>
</div>
);
}
export default App;
The error says that
Too many re-renders. React limits the number of renders to prevent an infinite loop.
You're setting the state inside the functional component body (The setFruit("apple") line) which will cause the component to re-render and when this happens all the component body will rerun again which will cause another set state call and so on which ultimately causes an infinite loop.
If you want to set the state when the component is mounting, You can use the useEffect hook to achieve that like so:
useEffect(() => {
setFruit("apple")
}, []);
Read more about the hook here.
you need to use useEffect
useEffect(() => {
setFruit("apple")
}, [])
The actual pattren of react is that when you set a state it cause rerender that means component re run again and recompile every line of code if it found a set state fucntion again it rerender and that's what happening in youe code. To prevent this you can use useEffect hook which accepts a callback function and a dependency array
For Example
useEffect(() => {}, []);
The code in every useEffect will run with first time component mount and if you want to run the code again you need to pass dependency in 2nd argument of useEffect which decide that if the dependency change it's value the code in useEffect will run again.
In your case you can set state like this
useEffect(() => {
setFruit("apple")
}, []);

What does it mean to 'move this variable directly inside useEffect' in this error message?

I am attempting to pass an object through props to a child component. The value is set in the useEffect hook and lost when passed to my child component.
I have tried setting the value of the object outside the useEffect hook in a separate function but the value is still lost.
import React, { useState, useEffect } from 'react';
function SetValue(props){
let users = {};
useEffect(() => {
users = { user: 'bob' };
})
return <NewComponent users={users} />
}
export default SetValue;
I expected props.users to be { user: 'bob' } and not an empty object {}.
The error message is:
"Assignments to the 'users' variable from inside React Hook useEffect will be lost after each render. To preserve the value over time, store it in a useRef Hook and keep the mutable value in the '.current' property. Otherwise, you can move this variable directly inside useEffect react-hooks/exhaustive-deps"
About useEffect hook:
By using this Hook, you tell React that your component needs to do something after render. React will remember the function you passed (we’ll refer to it as our “effect”), and call it later after performing the DOM updates. more
This means that function inside useEffect will be called after rendering of the component. That's why you have an empty object.
About the error. You have it because React doesn't remember your users variable - it will be recreated on each render of SetValue component. It will be better to use useState hook to set value in useEffect and remember it on the next render.
And one more note. Don't forget about passing the second argument in useEffect with an array of dependencies. Now your hook will be called after each render of SetValue component.
Here's how to use useState hook:
import React, { useState, useEffect } from 'react';
function SetValue(props){
const [users, setUsers] = useState({});
useEffect(() => {
setUsers({ user: 'bob' });
}, [
//here you could pass dependencies, or leave it empty to call this effect only on first render
]);
return <NewComponent users={users} />
}
export default SetValue;
This warning --"Assignments to the 'users' variable from inside React Hook useEffect will be lost after each render-- is the reason why state concept exists in React. React component doesn't preserve the value of normal javascript variables throughout successive re-renders(component lifecycle).Thats where react state helps so that changes to the state can be reflected in DOM if component re-renders.

Resources