Search code examples
reactjsuse-effect

run function once a value in an object has been updated


I have a list of objects that have multiple fields. I want to make an api call once the user has entered the location of the plant.

I thought of using useEffect, but that won't work since in order to make the api call, I need two values - id and index, and (as far as I know) you can't pass parameters in useEffect. I did it normally (which you can see in the code below), instead of using useEffect, but that doesn't work because the plant location is empty (as there is a bit of a delay before the plant location is updated).

So, how can I make the call once the plant location has been updated?

    //the plants object
    const [plants, setPlants] = useState([
        {
            name: 'Plant 1',
            id: uuidv4(),
            location: '',
            isOffshore: false,
            coords: {},
            country: '',
        }
    ])

    const handlePlantLocChange = (id, index, value) => {
        setPlants(
            plants.map(plant => 
                plant.id === id
                ? {...plant, location: value}
                : plant
            )
        )
        handler(id, index);
    }

    // this makes the api call. 
    //I need to pass id and index to this function 
    //no matter what, hence why I can't use useEffect
    const getCoords = (id, index) => {
        axios.get('http://localhost:3001/endpoints/coords', {
            params: {
                location: plants[index].location
            }
        }).then((response) => {
            if(response.status === 200) {
                handlePlantInfoChange(id, PlantInfo.COORD, response.data)
            }
        })
    }

    const handler = useCallback(debounce(getCoords, 4000), []);

    return (
        <div className='plant-inps-wrapper'>
            {
                plants.map((item, idx) => {
                    return (
                        <div key={item.id} className="org-input-wrapper">
                            <input placeholder={`${item.isOffshore ? 'Offshore' : 'Plant ' + (idx+1) + ' location'}`} onChange={(e) => handlePlantLocChange(item.id, idx, e.target.value)} value={item.isOffshore ? 'Offshore' : item.location} disabled={item.isOffshore} className="org-input smaller-input"/>
                        </div>
                     )
                })
            }
        </div>
    )


Solution

  • you can pass props and state to useEffect like this:

    useEffect(() => {
     getCoords(id, index);
    
     return () => getCoords(id, index);
    }, [id, index])