React Maximum update depth exceeded com SetInterval

Estou com um problema que não consigo resolver. Estou tentando simular a perda de água no corpo de um animal ao longo do tempo, e caso o animal esteja dormindo, a quantidade de água perdida é menor.

Dentro do primeiro UseEffect tenho um setInterval, que decrementa o estado currentValue de acordo com a prop water.decrementRate. Coloquei uma condição para que o setInterval execute somente se o animal estiver vivo. No retorno do hook eu limpo o loop com um clearInterval.

O programa funciona até o momento em que os valores da prop water.decrementRate ou do estado IsDead são alterados. No console do navegador o erro “React Maximum update depth exceeded.” ocorre iterativamente. Tentei usar as soluções que vi, colocando o array de dependencias para o useEffect, movendo a função “generateRandomNumber” para dentro do hook e utilizando Atualizações Funcionais no setState “setCurrentValue”.

Tenho o Seguinte código dentro do meu componente WaterSystem:

import { useState, useEffect } from "react";
import Container from "../Container/index"
import { useIsDead } from '../../hooks/animal.hook';
import './style.css';

const WaterSystem = ({water}) => {

    const (currentValue, setCurrentValue) = useState(water.capacity);
    const {isDead, setIsDead} = useIsDead();

    useEffect(() => {
        function generateRandomNumber() {
            const variationRate = 0.2;
            const variationValue = water.decrementRate  * variationRate;
            const max = (water.decrementRate + variationValue);
            const min = (water.decrementRate - variationValue);
            const newNumber = Math.random() * (max - min) + min;
            return newNumber;
        }

        if(!isDead){
            const id = setInterval(() => {
                setCurrentValue(oldValue => oldValue + (generateRandomNumber() * -1));
            }, 1000);
        
            return () => clearInterval(id);
        }
    }, (water.decrementRate, isDead)); 

    useEffect(() => {
        if(currentValue <= 0)
            setIsDead(true);
    }, (currentValue, setIsDead));

    useEffect(() => {
        if(!isDead){
            setCurrentValue(water.capacity);
        }
    }, (isDead, water.capacity));

    return(
        <Container>
            <p>Nivel de água (Máx <b>{water.capacity}</b> ml): <b>{currentValue.toFixed(2)}</b></p>
            <p>perda de água (ml/s): <b>{water.decrementRate}</b></p>
        </Container>
    );
}

export default WaterSystem;

Tenho o seguinte código no componente Animal:

import React from "react";

import WaterSystem from "../WaterSystem/index";
import Botao from "../Botao/index";
import { useWater, useIsDead, useIsSleeping } from '../../hooks/animal.hook';

import './style.css';

const Animal = () => {
  const {isSleeping, setIsSleeping} = useIsSleeping();
  const {isDead, setIsDead} = useIsDead();
  const water = useWater(isSleeping);

  return (
    <div>
      <h1>{isDead ? 'morto' : 'vivo'}</h1>
      <WaterSystem water={water} />
      <Botao label={isSleeping ? "awake" : "sleep"} onClick={() => setIsSleeping(!isSleeping)}/>
      {isDead && <Botao label="Reiniciar" onClick={() => setIsDead(!isDead)}/>}
    </div>
  )
};

export default Animal;

Neste arquivo estou usando 3 hooks customizados provenientes do arquivo animal.hook.js:

import { useState, useEffect, useContext } from "react";
import { AnimalContext } from "../contexts/Animal.context";

export function useWater(isSleep) {
    const values = {
        sleep: {
            capacity: 100,
            decrementRate: 6,
            drinkRate: 30,
            dehydrationRange: (0.05, 0.08, 0.1, 0.15)
        }, 
        repose: {
            capacity: 100,
            decrementRate: 10,
            drinkRate: 30,
            dehydrationRange: (0.05, 0.08, 0.1, 0.15)
        }
    };

    const (water, setWater) = useState(values.repose);

    useEffect(() => {
        if(isSleep)
            setWater(values.sleep);
        else    
            setWater(values.repose);
    }, (isSleep, values.sleep, values.repose));

    return water;
}

export function useIsDead() {
    const context = useContext(AnimalContext);
    const {isDead, setIsDead} = context;
    return {isDead, setIsDead};
}

export function useIsSleeping() {
    const context = useContext(AnimalContext);
    const {isSleeping, setIsSleeping} = context;
    return {isSleeping, setIsSleeping};
}

Na função useWater recebo um valor booleano isSleep para verificar se o animal esta dormindo e crio um objeto literal contendo os valores para cada condição do animal (dormindo e acordado). quando há mudança no isSleep, uso o useEffect para atribuir o corresponde valor no estado water e retorná-lo.

As funções useIsDead e useIsSleeping retornam os estados de um contexto criado para o animal, que está presente no arquivo Animal.context.js:

import React, { createContext, useState } from 'react';

export const AnimalContext = createContext({});

export const AnimalProvider = (props) => {
    
    const (isDead, setIsDead) = useState(false);
    const (isSleeping, setIsSleeping) = useState(false);

    return (
        <AnimalContext.Provider value={{ 
            isDead, setIsDead, 
            isSleeping, setIsSleeping
        }}>
            {props.children}
        </AnimalContext.Provider>
    );
}