Kanav Raina
Kanav Raina

Reputation: 43

useEffect getting called multiple times

When I am adding addData or updateData to the array of useEffect, it gets called infinite times,but i think it should only be called when button is clicked.

import axios from 'axios'
import { Button, TextField } from '@material-ui/core'
import React,{useState,useEffect} from 'react'
import { useDispatch, useSelector } from 'react-redux'
import Applebar from './MainPage/Applebar'
import './style.css'
import { add } from '../reducers/data/dataReducer'
import Loader from './Loader/Loader'
const Main = () => {
    const user=useSelector(state => state.auth);
    const dispatch=useDispatch()
    const [data,setData]=useState({
        site:"",
        uname:"",
        password:""
    })
    const handleChange=(e)=>{
        setData({...data, [e.target.name]:e.target.value})
    }
    
    const addData=async(e)=>{
        console.log('add fun  called')
        e.preventDefault()
        await axios.post('http://localhost:5000/data', data,{
            withCredentials: true 
         });
    }
    

    const userData=useSelector(state=>state.data)
    const arrData=userData.data
    const deleteData=async(id)=>{
        await axios.put("http://localhost:5000/data",{id},{
            withCredentials: true 
         })
    }

    const editData=(id)=>{
        const {data}=userData
        const reqdData=data.filter((d)=>{return (d._id==id)})
        const [getData]=reqdData
        setData(
        {
            site:getData.site,
            uname:getData.uname,
            password:getData.password
        })
        setCurrentId(id)
    }
    const [currentId,setCurrentId]=useState(null)
    const updateData=async()=>{
        if(currentId!==null)
            console.log(currentId)
            const updateData=await axios.put("http://localhost:5000/update",{...data,_id:currentId},{
                withCredentials: true 
             })
            console.log(updateData)
    }

    const getData=async()=>{
        const data=await axios.get('http://localhost:5000/data',{
            withCredentials: true 
         }).then((response)=>{
                dispatch(add(response.data))
            })    
        }

    useEffect(()=>{
        console.log("useeffect called")
        getData()
        
    },[dispatch])//, addData, updateData oncalling these function infinite calling
    
        return (
            <div>
                <Applebar />
                <h1>{user?.currentUser?.name}</h1>
                <div className="main_body">
                    <div className="main_form">
                            <form>
                                <div className="form_field">
                                    <TextField
                                    id="outlined-basic"
                                    name="site"
                                    label="site"
                                    variant="outlined"
                                    value={data.site}
                                    onChange={handleChange}/>
                                </div>
                                <div className="form_field">
                                    <TextField
                                     id="outlined-basic"
                                     name="uname"
                                     label="uname"
                                     variant="outlined"
                                     value={data.uname}
                                     onChange={handleChange}/>
                                </div>
                                <div className="form_field">
                                    <TextField
                                     id="outlined-basic" 
                                     name="password" 
                                     label="password" 
                                     variant="outlined" 
                                     value={data.password} 
                                     onChange={handleChange}/>
                                </div>
                                <div className="form_field">
                                    <Button onClick={addData} color="primary" variant="contained" >Add</Button></div>
                                <div className="form_field">
                                    <Button onClick={updateData} color="primary" variant="contained" >Update</Button></div>
                            </form>
                    </div>
                    <div className="main_data">
                        {arrData?.map((data)=>{
                                
                                return(
                                    <div key={data._id}>
                                        {data.site}
                                        <button onClick={()=>{deleteData(data._id)}}>-</button>
                                        <button onClick={()=>{editData(data._id)}}>editData</button>
                                    </div>
                                )
                        })}
                    </div>
                </div>
            </div>
        )
    }
//}

export default Main

Upvotes: 1

Views: 5721

Answers (2)

Riptide
Riptide

Reputation: 416

getData() updates the state, due to the dispatch to redux state, which causes the state to change, which in turn will re-render your component. On re-render all the defined functions will be redefined, hence the functions will change.

useEffect() will run everytime something in the dependency array changes, so it will run in an infinite loop due to the state changing and the functions being re-made every time the component re-renders.

You can use useCallback() to fix it. useCallback() will return any function defined inside it and will only redeclare the function when something in the useCallback() dependency array changes.

You can try to do this with your code

import {useCallback} from 'react'

    const addData= useCallback(async(e)=>{
        console.log('add fun  called')
        e.preventDefault()
        await axios.post('http://localhost:5000/data', data,{
            withCredentials: true 
         });
    }, [])

 const updateData=useCallback(async()=>{
        if(currentId!==null)
            console.log(currentId)
            const updateData=await axios.put("http://localhost:5000/update",{...data,_id:currentId},{
                withCredentials: true 
             })
            console.log(updateData)
    }, [])

    useEffect(()=>{
        console.log("useeffect called")
        getData()
        
    },[dispatch]) // now you can put those dependencies in this array,
// even though you only need to add getData. You don't even need dispatch here

Upvotes: 1

Akif Hadziabdic
Akif Hadziabdic

Reputation: 2890

useEffect(callback, dependencies) is the hook that manages the side-effects in functional components. The callback argument is a function to put the side-effect logic. dependencies is a list of dependencies of your side-effect: being props or state values.

useEffect(callback, dependencies) invokes the callback after initial mounting, and on later renderings, if any value inside dependencies has changed.

If you change one of the dependencies, the effect function will be executed. If you change a dependency in the effect function you will have an infinite loop.

Upvotes: 1

Related Questions