[英]How to await a setState call finishing when using useState hook that immediately needs that state to make an API call?
I have a voice dictation custom hook, along with a separate custom hook that appends the dictation results to an object that stores "Note" values. 我有一个语音听写自定义钩子,以及一个单独的自定义钩子,它将听写结果附加到存储“注释”值的对象。
If the user clicks save too early, there are still Partial Results that I need to append right before an API call that saves the Note. 如果用户过早点击保存,则仍然需要在保存Note的API调用之前追加部分结果。
My code looks like this 我的代码看起来像这样
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>
)
}
Problem is, the SaveNote is being called and is using the old state of the note...the setting of the state is not completing on time. 问题是,正在调用SaveNote并且正在使用笔记的旧状态...状态的设置未按时完成。
I can't seem to use a useEffect hook here to monitor the change, since I am calling the API to save the note right away and it's accessing the note state when saving. 我似乎无法在这里使用useEffect钩子来监视更改,因为我正在调用API来立即保存注释并且在保存时它正在访问注释状态。
What is the best way to handle this? 处理这个问题的最佳方法是什么? Thank you.
谢谢。
Try the useEffect hook: 试试useEffect钩子:
EDIT: Since it runs on first render you want to be sure the note object is not empty before saving 编辑:由于它在第一次渲染时运行,因此您希望在保存之前确保注释对象不为空
useEffect(() => {
if(Object.keys(note).length !== 0){
saveNote();
}
});
Given the updated code, you should be able to handle it very similarly to how I outlined in my original answer: 鉴于更新的代码,您应该能够像我在原始答案中概述的那样处理它:
// 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()
}
}
The key difference is that you only call saveNote
inside your press handler if you don't have a partial result. 关键的区别在于,如果您没有部分结果,
saveNote
在您的印刷机处理程序中调用saveNote
。 That way you don't get incomplete saves. 这样你就不会得到不完整的保存。 If you
setNote
, it will drop into your useEffect
and save with the right value. 如果你
setNote
,它将进入你的useEffect
并使用正确的值保存。
If this is a common pattern for handling these notes, it might make sense to move this logic into your useNote
hook. 如果这是处理这些注释的常用模式,则将此逻辑移动到
useNote
钩子中可能是有意义的。
Since you're using useState
for your note
value, you should be able to handle this with useEffect
. 由于您使用
useState
作为note
值,因此您应该能够使用useEffect
来处理它。 Values from useState
are immutable, so they work great as inputs for effects hooks. useState
中的值是不可变的,因此它们非常适合作为效果挂钩的输入。 Move your call to saveNote()
outside of handleSavePress
and into useEffect
: 将您的调用移到
saveNote()
之外的handleSavePress
saveNote()
并进入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 })
}
}
If, for some reason, your saveNote
function is defined inside this component, I would suggest moving it outside the component and passing it note
as an argument so you can be sure useEffect
will run only when you want it to. 如果由于某种原因,你的
saveNote
功能是该组件中定义的,我会建议移动它的组件外,并传递给它note
作为参数,所以你可以肯定useEffect
,当你希望它才会运行。 If there is some compelling reason why you need to define saveNote
inside the component, then you should define saveNote
with useCallback
and change your useEffect
function to key off changes to that: 如果有,为什么你需要定义一些令人信服的理由
saveNote
组件里面,那么你应该定义saveNote
与useCallback
和改变你的useEffect
功能键关机的变化是:
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 })
}
}
It's difficult to determine exactly where things might be going wrong without seeing a more complete code example. 如果没有看到更完整的代码示例,很难确切地确定出错的地方。 The
// ...Other misc code
section of your example is kind of important, particularly where and how you're defining saveNote
. // ...Other misc code
示例中的// ...Other misc code
部分非常重要,特别是在定义saveNote
位置和方式。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.