StateHasChanged not working in timers.

Hello, am trying to make a countdown timer to a specific date, it all works but for some reason even though I am calling StateHasChanged, it doesn't update, it only updates when I refresh the page. I also noticed that the dispose method (in the IDisposable interface) is called immediately after the page refreshes and the timer gets disposed instantly so it never has any time to run. .NET Version: 8.0.302
c#
@implements IDisposable

<span>@days, @hours, @minutes, @seconds</span>

@code {
private int days;
private int hours;
private int minutes;
private int seconds;

private Timer? timer;

protected override void OnInitialized()
{
StartTimer();
}

private void StartTimer()
{
DateTime targetDate = new DateTime(2024, 12, 31, 23, 59, 59);
UpdateCountdown(targetDate);

timer = new Timer(state =>
{
UpdateCountdown(targetDate);
InvokeAsync(StateHasChanged);
}, null, 0, 1000);
}

private void UpdateCountdown(DateTime targetDate)
{
var timeSpan = targetDate - DateTime.Now;

if (timeSpan.TotalSeconds < 0)
{
days = 0;
hours = 0;
minutes = 0;
seconds = 0;
timer?.Dispose();
}
else
{
days = timeSpan.Days;
hours = timeSpan.Hours;
minutes = timeSpan.Minutes;
seconds = timeSpan.Seconds;
}
}

public void Dispose()
{
timer?.Dispose();
}
}
c#
@implements IDisposable

<span>@days, @hours, @minutes, @seconds</span>

@code {
private int days;
private int hours;
private int minutes;
private int seconds;

private Timer? timer;

protected override void OnInitialized()
{
StartTimer();
}

private void StartTimer()
{
DateTime targetDate = new DateTime(2024, 12, 31, 23, 59, 59);
UpdateCountdown(targetDate);

timer = new Timer(state =>
{
UpdateCountdown(targetDate);
InvokeAsync(StateHasChanged);
}, null, 0, 1000);
}

private void UpdateCountdown(DateTime targetDate)
{
var timeSpan = targetDate - DateTime.Now;

if (timeSpan.TotalSeconds < 0)
{
days = 0;
hours = 0;
minutes = 0;
seconds = 0;
timer?.Dispose();
}
else
{
days = timeSpan.Days;
hours = timeSpan.Hours;
minutes = timeSpan.Minutes;
seconds = timeSpan.Seconds;
}
}

public void Dispose()
{
timer?.Dispose();
}
}
1 Reply
SleepWellPupper
What rendermode is the component being rendered in?