我有一个语音听写自定义 Hook ,以及一个单独的自定义 Hook ,该 Hook 将听写结果附加到存储“音符”值的对象。
如果用户过早点击保存,我仍然需要在保存注释的 API 调用之前追加部分结果。
我的代码是这样的
function NoteDictation(props) {
const [
results,
partialResults,
error,
toggleRecognizing,
speechHasStarted,
] = useDictation();
const [note, setNote, saveNoteAPICall, updateNoteAPICall] = useNote({})
//Use Note is a custom hook that has that certain type of note's properties built in (they're medical notes, and we have a custom hook for each type of note).
function handleSavePress(){
if(partialSpeechResults){
//If the dictation software hasn't returned a final result,
//append the partialSpeechResults
setNote({...note, text: note.text + partialSpeechResults})
}
//SaveNote does not use the value set above if there are partial results.
saveNote()
}
return (
<View>
<NoteContents note={note} results={results} partialResults={partialResults} />
<Button onPress={handleSavePress> />
</View>
)
}
问题是,正在调用 SaveNote 并使用笔记的旧状态...状态设置未按时完成。
我似乎无法在此处使用 useEffect Hook 来监视更改,因为我正在调用 API 以立即保存笔记,并且它在保存时访问笔记状态。
处理此问题的最佳方法是什么?谢谢。
最佳答案
编辑
鉴于更新后的代码,您应该能够以与我在原始答案中概述的方式非常相似的方式处理它:
// will run on mount and whenever note changes
useEffect(() => {
// skip first run (what you check depends on your initial note value)
if (Object.keys(note).length) {
saveNoteAPICall()
}
}, [note])
function handleSavePress(){
if(partialSpeechResults){
// If the dictation software hasn't returned a final result,
// append the partialSpeechResults
// and let if fall into useEffect when note updates
setNote({...note, text: note.text + partialSpeechResults})
} else {
// run immediately if not partial
saveNoteAPICall()
}
}
主要区别在于,如果您没有部分结果,您只能在新闻处理程序中调用 saveNote
。这样你就不会得到不完整的保存。如果您 setNote
,它将放入您的 useEffect
并以正确的值保存。
如果这是处理这些注释的常见模式,那么将此逻辑移至您的 useNote
Hook 中可能是有意义的。
原始答案
因为您正在为您的 note
值使用 useState
,所以您应该能够使用 useEffect
来处理它。 useState
中的值是不可变的,因此它们非常适合用作效果 Hook 的输入。将对 saveNote()
的调用从 handleSavePress
移到 useEffect
中:
const [note, setNote] = useState({})
// ...Other misc code
// this will run on first execution,
// and then any time the value of note changes
useEffect(() => {
// skip first run
if (Object.keys(note).length) {
saveNote(note)
}
}, [note])
function handleSavePress(){
if (partialSpeechResults) {
// If the dictation software hasn't returned a final result,
// append the partialSpeechResults
setNote({ ...note, text: note.text + partialSpeechResults })
}
}
如果出于某种原因,您的 saveNote
函数是在该组件内定义的,我建议将其移至组件外部并将其作为参数传递给 note
,这样您就可以确保 useEffect
仅在您需要时运行。如果有一些令人信服的理由需要在组件内部定义 saveNote
,那么您应该使用 useCallback
定义 saveNote
并更改您的 使用 Effect
函数来关闭对其的更改:
const [note, setNote] = useState({})
// ...Other misc code
// this function will only change when note changes
const saveNote = useCallback(() => {
// whatever api call you need to run here
// that uses the note value in scope
}, [note])
// this will run on first execution,
// and then any time the value of note (and thus saveNote) changes
useEffect(() => {
// skip first run
if (Object.keys(note).length) {
saveNote()
}
}, [saveNote, note])
function handleSavePress(){
if (partialSpeechResults) {
// If the dictation software hasn't returned a final result,
// append the partialSpeechResults
setNote({ ...note, text: note.text + partialSpeechResults })
}
}
在没有看到更完整的代码示例的情况下,很难准确地确定哪里出了问题。您的示例的 //...Other misc code
部分很重要,尤其是您定义 saveNote
的位置和方式。
关于javascript - 使用立即需要该状态进行 API 调用的 useState Hook 时,如何等待 setState 调用完成?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57138642/