在 React 中,有一个父组件,它根据是否有选定的线程有条件地渲染
Output
组件:
<div className="flex-grow overflow-y-auto p-4">
{myStore.selectedThread ? (
<Suspense
fallback={
<div className="flex justify-center items-center align-middle h-full">
<Loader active={true} className="w-36 h-36" />
<p className="text-xs text-gray-500">Loading messages...</p>
</div>
}
>
<Output loading={loading} />
</Suspense>
) : (
<div className="flex flex-col items-center justify-center h-full">
<h1 className="text-6xl font-bold text-violet-900 mb-4">
Hi, {store.profile.fname} {store.profile.lname}!
</h1>
<p className="text-gray-500 text-xl mb-8">
Hit record and let the magic begin.
</p>
<RecordingComponent myStore={myStore} />
</div>
)}
</div>
并且,在父组件内的
RecordingComponent
中,我在 handlePostTranscription()
函数之后使用 MobX 存储函数选择一个线程:
const audioTranscriberStatus =
myStore.inputActiveRecord?.audioTranscriber?.status;
console.log(audioTranscriberStatus);
useEffect(() => {
const handlePostTranscription = async () => {
const { inputActiveRecord, selectedThread } = myStore;
if (!inputActiveRecord || selectedThread) {
return;
}
try {
const newThread = await createThread();
const newThreadId = newThread.thread_id;
setForceRender((prev) => !prev);
await updateHistory(inputActiveRecord._id, { threadId: newThreadId });
const transcriptionText = inputActiveRecord.outputs.join(" ");
await addMessage(newThreadId, "user", transcriptionText);
await runAssistant(
transcriptionText,
newThreadId,
"asst_L24bszgfqSOxw3yT0dTOaIzZ",
"",
);
myStore.selectThread(newThreadId);
console.log(myStore.selectedThread);
} catch (error) {
console.error("Error in post-transcription handling:", error);
}
};
if (audioTranscriberStatus === "done") {
handlePostTranscription();
}
}, [audioTranscriberStatus]);
在调试日志中,我可以看到它正确设置了线程,这意味着
myStore.selectedThread
为 true,应该渲染 Output
组件。
但是,我的问题是在父组件中,
Output
没有渲染——我仍然看到欢迎屏幕。当我使用 HistoryPanel
组件或 TextInputComponent
组件设置线程时,情况并非如此。它们似乎都使 Output
组件渲染成功。
来自
TextInputComponent
:
const handleTextSubmit = async () => {
try {
setLoading(true);
// Save the text using the API that goes through the middleware
const response = await saveText(message);
if (response.data.history && response.data.history._id) {
const fetchedHistory = response.data.history;
let currentThreadId = fetchedHistory.threadId;
if (!currentThreadId) {
// Create a new thread if none exists
const newThread = await createThread();
currentThreadId = newThread.thread_id;
// Update history with the new thread ID
await updateHistory(fetchedHistory._id, {
threadId: currentThreadId,
});
}
// Add the message to the thread
await addMessage(currentThreadId, "user", message);
// Run the assistant on the message
await runAssistant(
message,
currentThreadId,
"asst_L24bszgfqSOxw3yT0dTOaIzZ",
"",
);
myStore.selectThread(currentThreadId);
}
} catch (error) {
console.error(error);
} finally {
setMessage("");
setLoading(false);
}
};
来自
HistoryPanel
:
const handleHistoryClick = async (threadId) => {
try {
setSelectedThreadId(threadId);
myStore.selectThread(threadId);
} catch (error) {
console.error("Error selecting thread:", error);
}
};
最后,我的商店:
selectThread = async (threadId) => {
if (this.selectedThread !== threadId) {
this.selectedThread = threadId;
await this.fetchThreadMessages(threadId);
}
};
请问有人知道是什么原因造成的吗?
我还尝试将查询参数添加到具有
threadId
的 url 中,并在 url 具有此参数时渲染 Output
组件,但是,在 handlePostTranscription()
函数中,当我使用 window.location.href
甚至useHistory
,它甚至没有改变网址。所以异步函数肯定有什么东西搞砸了。
您已更改
myStore
上的对象属性,但 React 只监视外部对象,而不是其属性。
当你改变它所监视的内容时,React 会更新 DOM;然后它可以重新运行您的函数或重新渲染您的组件并对 DOM 进行更改。
我们看不到您的
myStore
,但即使它是 useState
变量,它们也只能使用 Object.is
通过 浅相等进行比较。你已经改变了它的状态,但 React 不知道要注意这一点。你的 TextInputComponent 和 HistoryPanel 意外地通过它们的
setMessage
、setLoading
和 setSelectedThreadId
触发了这个,这可能会以 React 可以看到的方式改变状态变量; myStore
的更新是在您的两个工作组件中意外发生的。
尽管有一些令人沮丧的方法来强制重新渲染(请参阅可以在不调用 setState 的情况下强制 React 组件重新渲染吗?),但最好的选择可能是调用
setSelectedThreadId
或创建一个新的状态变量(例如 setTranscriptionUpdateTimestamp
)将数据更改反映到您尝试更新的组件。