Wrote some code to compile results from different projects and update useState hook, doesn't work as expected.
PS - adding dependency in useEffect's argument to redo the function twice to update itself isn't helping either.
Briefing for easy understanding of whats going on in code:
- I have a multiple-selection input field.
- Based on input values, a useState 'selectedProjectScopeData' gets updated after running an api call through another function.
- I calculate the total sum from the above mentioned state and store it in another state 'summedSelectedProjectScopeData' to display in react
- Issue - The result I get is always one stage lagging behind, the state is not working with updated values.
const classes = useStyles();
const { approvedProjects } = useSelector(state => state.finance)
const { userDetails } = useSelector(state => state.user)
const buttonRef = useRef(null)
const [selectedProjectsScopedData, setSelectedProjectsScopedData] = useState([]);
const [summedSelectedProjectsScopedData, setSummedSelectedProjectsScopedData] = useState({Carpentry: {areaOrQty:0, materialRequested: 0, tdp:0, poRequested:0, soRequested:0}, Procurement_Others: {areaOrQty:0, materialRequested: 0, tdp:0, poRequested:0, soRequested:0}, Modular:{areaOrQty:0, materialRequested: 0, tdp:0, poRequested:0, soRequested:0}, Services:{areaOrQty:0, materialRequested: 0, tdp:0, poRequested:0, soRequested:0}, Hardware:{areaOrQty:0, materialRequested: 0, tdp:0, poRequested:0, soRequested:0}})
const [scopeModal, setScopeModal] = useState(false)
const [scopedProducts, setScopedProducts] = useState([])
const [scope, setScope] = useState("")
const [projectInfo, setProjectInfo] = useState([])
const [toggle, setToggle] = useState(false)
useEffect(() => {
getApprovedProjects()
// eslint-disable-next-line
}, [])
// useEffect(()=>{
// ProjectDetailsAccumulator();
// console.log('selectedProjectsScopedData is ',selectedProjectsScopedData)
// console.log('summedSelectedProjectsScopedData is ',summedSelectedProjectsScopedData)
// },[selectedProjectsScopedData])
// useEffect(() => {ProjectDetailsAccumulator()},[selectedProjectsScopedData])
// runs the http request and adds data in the required array
const getProjectsScopedData = async (projectId, newArr) =>{
// console.log("Function 2: Step 1 : getProjectsScopedData runs")
try{ //If data is not found we call make an httpcall for that data and add it to the array
const response = await HttpService.getProjectsScopedData(projectId)
const newData = await response.data;
// console.log("Function 2: Step 2 : http request runs and gives newData as ",newData);
newArr.push(newData) //adding data to array of selected projects
}
catch(error){
console.log(error)
props.setSnackInfo(error?.response?.data?.message ?? "Error while fetching project scope data", "error")
}
}
//runs when the projects in multiple selection changes
const changeHandler = async (event,values) => {
// console.log("Function 1: Step 1 : change handler runs")
try {
props.setLoading(true)
let newArr = [] // new array to store the new project data called from ==> const response = await HttpService.getProjectsScopedData(projectId)
// console.log("Function 1: Step 2: values recieved are : ", values)
values.forEach((selectedValue) => { // values contain project details and projectId
const foundProject = selectedProjectsScopedData.find((projectElement) => {
return projectElement.projectId === selectedValue._id;
});
if(foundProject) {
newArr.push(foundProject)
}
else{
getProjectsScopedData(selectedValue._id,newArr)
}
})
// console.log("Function 1: Step 3: newArr to be fed into state is", newArr)
setSelectedProjectsScopedData(newArr); // we assign the data to the selectedProjectsScopedData state
ProjectDetailsAccumulator()
props.setLoading(false)
}
catch(error){
console.log(error);
props.setLoading(false)
props.setSnackInfo("Couldn't fetch Projects Scoped Data", "error")
}
}
//runs at the end of changeHandler to sum up details from all the projects that are selected
const ProjectDetailsAccumulator = ()=>{
try{
let ProjectDetails = {Carpentry: {areaOrQty:0, materialRequested: 0, tdp:0, poRequested:0, soRequested:0}, Procurement_Others: {areaOrQty:0, materialRequested: 0, tdp:0, poRequested:0, soRequested:0}, Modular:{areaOrQty:0, materialRequested: 0, tdp:0, poRequested:0, soRequested:0}, Services:{areaOrQty:0, materialRequested: 0, tdp:0, poRequested:0, soRequested:0}, Hardware:{areaOrQty:0, materialRequested: 0, tdp:0, poRequested:0, soRequested:0}}
//iterating through all the projects in the selectedProjectsScopedData
// console.log('Function 3: STEP 1: selectedProjectsScopedData is: ', selectedProjectsScopedData)
// console.log('Function 3: STEP 1: selectedProjectsScopedData[0] is: ', selectedProjectsScopedData[0])
// console.log('Function 3: STEP 1-1: selectedProjectsScopedData.length is is: ', selectedProjectsScopedData.length)
selectedProjectsScopedData.forEach((iproject)=>{
console.log('inside forEach loop')
for(const itype of iproject.result){ //Accessing object for each type from result array of types
const currenttype = itype?.type
// console.log('+itype?.totalDecorpotPrice is', +itype?.totalDecorpotPrice)
ProjectDetails[currenttype].areaOrQty += itype?.area ? (+itype?.area || 0) : (+itype?.quantity || 0);
ProjectDetails[currenttype].tdp += +itype?.tdp || 0;
ProjectDetails[currenttype].poRequested += +itype?.poRequested || 0
ProjectDetails[currenttype].soRequested += +itype?.soRequested || 0
ProjectDetails[currenttype].materialRequested += +itype?.materialRequested || 0
}
})
// console.log('Function 3 : STEP 2: project details are', ProjectDetails);
setSummedSelectedProjectsScopedData(ProjectDetails);
}
catch(error){
console.log(error.message)
}
}
I tried putting both states in useEffects argument with the function that updates it, but it threw the code into an obvious infinte loop in that case.