使用立即需要该状态进行 API 调用的 useState 挂钩时,如何等待 setState 调用完成?
Posted
技术标签:
【中文标题】使用立即需要该状态进行 API 调用的 useState 挂钩时,如何等待 setState 调用完成?【英文标题】:How to await a setState call finishing when using useState hook that immediately needs that state to make an API call? 【发布时间】:2019-11-29 23:51:22 【问题描述】:我有一个语音听写自定义挂钩,以及一个单独的自定义挂钩,该挂钩将听写结果附加到存储“Note”值的对象。
如果用户过早点击保存,我仍然需要在保存注释的 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 挂钩来监视更改,因为我正在调用 API 来立即保存便笺,并且在保存时它正在访问便笺状态。
处理此问题的最佳方法是什么?谢谢。
【问题讨论】:
目前useState hook中的setState不支持回调。但是您可以使用 useEffect 挂钩来执行“渲染后”回调并与当前状态值协调。 是的,理解,但如上所述,我有一个独特的情况,我在之后立即使用该值将其保存在 API 调用中。 也许这个答案可以帮助你***.com/questions/53446020/…。 【参考方案1】:编辑
鉴于更新的代码,您应该能够非常类似于我在原始答案中概述的方式来处理它:
// 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
挂钩中可能是有意义的。
原答案
由于您使用useState
作为您的note
值,您应该能够使用useEffect
处理此问题。 useState
中的值是不可变的,因此它们可以很好地作为效果挂钩的输入。将您的电话移至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 )
如果由于某种原因,您的 saveNote
函数在此组件内定义,我建议将其移到组件外并将 note
作为参数传递,这样您就可以确保 useEffect
仅在您运行时运行想要它。如果有一些令人信服的理由需要在组件内定义 saveNote
,那么您应该使用 useCallback
定义 saveNote
并更改您的 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 )
如果没有更完整的代码示例,很难准确地确定哪里出了问题。您示例的 // ...Other misc code
部分非常重要,尤其是您在何处以及如何定义 saveNote
。
【讨论】:
感谢您的详细评论。刚刚用更多细节更新了我的代码。基本上,我将 useDictation 钩子的结果输入到我的组件中,如果在数组之前仍有部分结果返回,我想将其添加到注释中。我有多个钩子,其中包含 saveAPICalls,因此,如果我必须更新函数以接收笔记与在钩子内访问它,我必须更新很多钩子(我们有很多笔记类型)。 这将是一个令人信服的理由来定义它内联:) 呵呵 :) 不幸的是,我不能对笔记上的每个状态更新都进行 API 调用,这会杀死我的 AWS 账单 :)【参考方案2】:试试 useEffect 钩子:
编辑:因为它在第一次渲染时运行,所以你要确保在保存之前笔记对象不为空
useEffect(() =>
if(Object.keys(note).length !== 0)
saveNote();
);
【讨论】:
如果我理解正确,这是行不通的,因为这样它会在依赖项的每次更改或挂载时触发。 正确——这将在每个渲染上运行,这对你的 api 来说不是很好。你需要一个依赖数组来防止它失控。 可以在调用saveNote函数之前检查note对象是否为空。 @stephenlizcano以上是关于使用立即需要该状态进行 API 调用的 useState 挂钩时,如何等待 setState 调用完成?的主要内容,如果未能解决你的问题,请参考以下文章
React Hooks:使用useState更新状态不会立即更新状态[重复]