fix(ui): enforce idempotent AI data fetching and JSRuntime guards
This commit is contained in:
@@ -51,9 +51,13 @@
|
||||
private string _lastFetchedBlockId = string.Empty;
|
||||
private KnowledgePacket? _packet;
|
||||
private CancellationTokenSource? _streamCts;
|
||||
private bool _isInteractive;
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
if (!_isInteractive)
|
||||
return;
|
||||
|
||||
// Only re-fetch when the block context actually changes
|
||||
if (string.IsNullOrEmpty(ContextBlockId) || ContextBlockId == _lastFetchedBlockId)
|
||||
return;
|
||||
@@ -62,6 +66,19 @@
|
||||
await FetchAndStreamAsync();
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
_isInteractive = true;
|
||||
if (!string.IsNullOrEmpty(ContextBlockId))
|
||||
{
|
||||
_lastFetchedBlockId = ContextBlockId;
|
||||
await FetchAndStreamAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task FetchAndStreamAsync()
|
||||
{
|
||||
// Cancel any in-progress stream
|
||||
|
||||
@@ -26,15 +26,40 @@
|
||||
|
||||
private GroundednessResult? _result;
|
||||
private bool _isChecking;
|
||||
private bool _isInteractive;
|
||||
private string _previousAnswer = string.Empty;
|
||||
private string _previousContext = string.Empty;
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
if (Answer != _previousAnswer || Context != _previousContext)
|
||||
{
|
||||
_result = null;
|
||||
_previousAnswer = Answer;
|
||||
_previousContext = Context;
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Answer) && !string.IsNullOrEmpty(Context) && _result == null)
|
||||
if (_isInteractive && !string.IsNullOrEmpty(Answer) && !string.IsNullOrEmpty(Context) && _result == null)
|
||||
{
|
||||
await RunCheck();
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
_isInteractive = true;
|
||||
if (!string.IsNullOrEmpty(Answer) && !string.IsNullOrEmpty(Context) && _result == null)
|
||||
{
|
||||
await RunCheck();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task RunCheck()
|
||||
{
|
||||
_isChecking = true;
|
||||
|
||||
@@ -27,11 +27,10 @@
|
||||
private IJSObjectReference? _keydownHandler;
|
||||
private DotNetObjectReference<Home>? _dotNetRef;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
QuizState.OnQuizRequested += HandleQuizRequestedAsync;
|
||||
FocusMode.OnFocusModeChanged += HandleUpdate;
|
||||
await FocusMode.InitializeAsync();
|
||||
}
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
@@ -65,11 +64,13 @@
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
await FocusMode.InitializeAsync();
|
||||
try {
|
||||
_interopModule = await JS.InvokeAsync<IJSObjectReference>("import", "./_content/NexusReader.UI.Shared/js/focusInterop.js");
|
||||
_dotNetRef = DotNetObjectReference.Create(this);
|
||||
_keydownHandler = await _interopModule.InvokeAsync<IJSObjectReference>("attachKeyboardListener", _dotNetRef);
|
||||
} catch { } /* ignored dynamically */
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user