Array is Updating with useEffect but Always Get the Initial Value - reactjs

This question has been asked many times but none of the solutions have worked for me. I miss something and I need your help to find it out.
I also provide the whole code to give you context.
I have a TV app that shows the production of a factory.
Initially I request the server to check if statically defined lines are working right now.
let lineIds = ["3", "1", "9"]
TvApp.getInitialProps = async (ctx) => {
try {
const res = await axios.get(`http://192.168.1.10:8090/api/tv_app_checkline/:${lineIds}`)
const workingLinesResponse = await res
console.log('workingLinesResponse: data: ', workingLinesResponse.data)
return { workingLines: workingLinesResponse.data }
} catch (error) {
console.log('error getInitialProps:: ', error)
return { data: null }
}
}
In the first useEffect, I keep checking every 15 seconds if the lines are still working;
Server responds with the workingLines.
In the second useEffect, I use workingLines to get production data for the currently working lines.
My problem is;
In the first useEffect, setWorkingLines(response.data) is updating workingLines but cannot be used by the second useEffect. Second useEffect always shows the initial value.
export default function TvApp(props) {
const [workingLines, setWorkingLines] = useState(props.workingLines);
//first useEffect
useEffect(() => {
const timer = setInterval(() => {
const API = `http://192.168.1.10:8090/api/tv_app_checkline/:${lineIds}`
axios.get(API)
.then(response => {
console.log('workingLines initially:: ', response.data)
setWorkingLines(response.data)
})
.catch(error => {
console.log(error.message);
});
return () => clearInterval(timer);
}, 15000);
},[])
var activeLineId = 0
//second useEffect
useEffect(() => {
const timer = setInterval(() => {
axios.get(`http://192.168.1.10:8090/api/tv_app/:${workingLines[activeLineId]}`)//workingLines is always the initial value, not updated one.
.then(response => {
//Set reponse to use in the view.
})
if (activeLineId === workingLines.length - 1) {
activeLineId = 0
} else {
activeLineId = activeLineId + 1
}
return () => clearInterval(timer);
}, 10000);
}, []); //using workingLines as a dependency is causing the multiple api requests
}
If I use workingLines as a dependency in the second useEffect, the api request is calling multiple times.
I can check the workingLines with following useEffect:
useEffect(() => {
console.log('workingLines:: ', workingLines) //this shows that, workingLines is successfully updated by the first useEffect
}, [workingLines])
How can I use the updated workingLines in the second useEffect without calling the api multiple times?

Related

Trying to render 2 methods on useEffect but getting only one's Result

I am trying to render 2 methods on useEffect but the problem is they both get rendered but somehow the method which gets rendered at 2nd place replaces the content of first method
In short: I am only getting output of 2nd method, first method's output is watchable for a sec then dissapears
I tried it on 2 ways -
1st way -
useEffect(() => {
getPages();
getFeatures();
}, []);
I am getting result of only getFeatures(), getPages() dissapears() after a sec..
2nd way -
useEffect(() => {
getFeatures();
console.log("featFeatures");
}, []);
useEffect(() => {
getPages();
console.log("getPages");
}, []);
Same here, I am getting both console logs but result of only 2nd UseEffect, 1st UseEffect result gets dissapear after 2nd useEffect runs
Any Solution for this guys?
getPage() -
const getPages = async () => {
await getAllPagesFromUser(pageSkip, pageLimit, token).then((data) => {
if (data.error) {
console.log(data.error);
} else {
setValues({ ...values, pages: data });
}
});
};
GetFeatures()-
const getFeatures = () => {
getAllFeaturesFromUser(featureSkip, featureLimit, token).then((data) => {
if (data.error) {
console.log(data.error);
} else {
setValues({ ...values, features: data });
}
});
};
It is because both functions trying to set state at the same time.
you can do this,
const loadData = async ()=>{
await getPages();
getFeatures();
}
and update useEffect
useEffect(() => {
loadData()
}, []);

useEffect race condition with Redux

Hello I have been struggling to set values when mounting a component. I am using useEffect Hook and useDispatch, useSelector for calling methods and also getting the state from the store. The problem is that the state from the store is delayed 1 render and therefore I need to run two times the code inside useEffect in order to get the behavior I expect. Which is -> when the component loads, do an API call and list some documents.
Data declaration
const data = useSelector(state => state.whole.manufactured);
useEffect code
useEffect(() => {
if (counter <= 1) {
fetchData();
setProducts(data);
setCounter(counter + 1);
}
console.log('data in store', data);
console.log('useEffect');
}, [clickedItem, data]);
fetchData function
const fetchData = async () => {
await dispatch(get_manufacturing());
};
get_manufacturing
return dispatch => {
dispatch(Actions.uiStartLoading());
fetch('http://myapi/api/product/get-products', {
method: 'GET',
headers: Interceptor.getHeaders(),
})
.then(res => res.json())
.then(result => {
dispatch(Actions.uiStopLoading());
if (result.status === true) {
dispatch({type: TYPES.GET_MANUFACTURABLE, data: data});
}
})
.catch(error => {
dispatch(Actions.uiStopLoading());
console.log(error);
});
When this code runs, the following happens.
As you can see in the first render it seems it just completely ignorees the fetchData() and proceeds to the console.log, after the second render the values have been properly set. How can I resolve this issue is there something I'm not getting properly done?
Replace clickedItem in the dependency list with counter.

Variable doesn't initialize after async function

I am making a request like this:
const createProgramari = async () => {
let prog = [];
try {
await axios.get('http://localhost:8000/api/programariByDentistID', {
params: {
id: JSON.parse(localStorage.getItem('user'))["id"]
}
})
.then(function (res) {
console.log(res);
if(res.status === 200) {
prog = res.data;
}
})
.catch(function (error) {
console.log(error);
});
setProgramari(prog);
} catch(e) {
console.log(e);
}
}
If I try to see this in my useEffect the variable 'programari' is an empty array (the value I initialized it with)
const [programari, setProgramari] = useState([]);
useEffect( () => {
// code to run on component mount
createProgramari();
console.log(programari);
}, [])
I tried printing the response and axios gets it right.
What am I doing wrong? Is there a place I could learn how to not do the same mistake?
The salient point here is that setProgramari is async in nature. If it is called, it doesn't necessarily imply that it will be executed right away. One way you can handle this is follows.
useEffect(() => {
createProgramari();
}, []);
// consider useMemo or useCallback based on your use case if need be
useEffect(() => {
// whatever logic you want to have
console.log(programari); // will get new value always
}, [programari])
The way you wrote the function is very confusing, I'd suggest refactoring this to
const createProgramari = async () => {
try {
const prog = (await axios.get('http://localhost:8000/api/programariByDentistID', {
params: {
id: JSON.parse(localStorage.getItem('user'))["id"]
}
})).data;
setProgramari(prog);
} catch (e) {
console.log(e)
}
}
To view data you can do something like this:
useEffect(() => {
createProgramari()
.then((someReturnedDataFromAPI) => { // Promise returned
console.log(programari)
})
}, []) // Initialization
in useEffect programari is equal with [] because setProgramari() not update already existed state in current component version, if set new state for programari, this modification propagate rerendering component
console.log(programari) work with current component state version
if you want dump programari you can move console.log outsite useEffect
in this case you get in console two dump - [] for first version and [ withData ] for version what rerender because setState()
or if you want use data from axios in useEffect you can return it how promise

setState never gets set in useEffect after API call responds with data

I'm trying to update state immediately after data comes in from the API. The data is coming in, I can see it using the console.log right below my API request. All of the data is right but for some reason, setState never sets in my hook. It just returns and empty array even after the console displays data.
const [experienceData, setExperienceData] = useState([]);
const { match = {} } = props;
useEffect(() => {
async function fetchData() {
if (Object.keys(match.params).length > 0) {
const response = await ApiService.getExperiences(match.params.experieneId);
console.log(response)
setExperienceData(response)
}
}
fetchData();
}, []);
I must be doing something wrong but I can't figure out what that is. Hoping someone on here has run into the same issue.
UPDATE: I just changed everything over the a class and duplicated the exact code on another file and ran into the exact same issue. The console updates with the data, but the setState on the line immediately after the data does not setState.
async componentDidMount() {
if (Object.keys(this.props.match.params).length > 0) {
const response = await ApiService.getExperiences(this.props.match.params.experieneId);
console.log(response[0])
this.setState({ experienceData: response[0], occurrenceData: response[0].occurrences });
}
}
You have to useSetState in a proper way, the issue is in the setExperienceData
const [experienceData, setExperienceData] = useState({response:""});
const { match = {} } = props;
useEffect(() => {
async function fetchData() {
if (Object.keys(props.match.params).length > 0) {
const response = await ApiService.getExperiences(match.params.experieneId);
console.log(response)
setExperienceData(experienceData => ({ ...experienceData, response: response }));
}
}
fetchData();
}, []);
return(<div>check {experienceData.response}</div>)
I see you left the dependency array empty. This tells React to run this effect only once: when the component first renders. If you want your useEffect to respect your state hook, put setExperienceData inside the dependency array
const [experienceData, setExperienceData] = useState([]);
const { match = {} } = props;
useEffect(() => {
fetchData();
}, [props.match.params]);
const async fetchData = () => {
if (Object.keys(match.params).length > 0) {
const response = await ApiService.getExperiences(match.params.experieneId);
console.log(response)
setExperienceData([...response])
}
}
Could you please try passing [match.params] as the second argument to your useEffect.

React Hook setting state in useEffect with state in dependency array

I have a question about the correct usage with useEffect and setState in React Hooks.
here is my react app that gets a persisted configuration and some other data depending on the config like this:
function App() {
const [config, setConfig] = useState(null);
// some other states
useEffect(() => {
const fetchData = () => {
axios.get("/path/to/config").then(response => {
if (response.status === 200) {
return response.data
}
})
.then(data => {
setConfig(data.config);
// set some other states
})
.catch(error => {
console.log("Error:" + error);
})
}
fetchData();
}, [config]);
return (
<div >
...
</div>
);
}
If I run this App useEffect is instantly called twice one time for first render and then a second time because setConfig(data.config); is called in the axios get success function.
The user has the possibility to change his own config that is done in another request. If he does I want after state config changes that the config and some other data depending on the config is reloaded via this useEffect function.
Now since there is no setstate callback in react hooks I read somewhere I should use useEffect with the state variable in the dependency array.
How can I prevent that my useEffect is called twice right at the beginning?
I have the feeling that I am doing it all wrong.
Thank you in advance
You need to add an if condition in useEffect, because useEffect is called by default on first render.
useEffect(() => {
if(config !== null){
const fetchData = () => {
axios.get("/path/to/config").then(response => {
if (response.status === 200) {
return response.data
}
})
.then(data => {
setConfig(data.config);
// set some other states
})
.catch(error => {
console.log("Error:" + error);
})
}
fetchData();
}
}, [config]);
This is not right!
I guess this can call fetchData infinitely.

Resources