如何在setState执行完成后调用函数?传第二个参数报参数数量错误
报错原因
你调用的setPou2是React函数组件中useState Hook返回的状态更新函数,它和类组件的this.setStateAPI设计并不一致:
- 类组件的
this.setState原生支持第二个入参作为回调函数,会在状态更新完成、组件重渲染结束后执行 - 函数组件的
useState返回的状态更新函数只接收1个入参,入参可以是新的状态值,也可以是返回新状态的纯更新函数,本身没有设计第二个回调参数的位置,TypeScript做类型校验时自然会抛出Expected 1 arguments, but got 2的参数数量不匹配错误。
注意不要尝试在调用setPou2的同步代码后直接写后续逻辑,受闭包影响,同步位置拿到的还是更新前的旧状态值,逻辑会不符合预期。
正确实现方式
方案1:useEffect监听状态变化(官方推荐)
useEffect会在组件完成重渲染、状态更新落地后执行,和类组件setState回调的执行时机完全一致,是官方推荐的等价实现:
import { useState, useEffect } from 'react' // 组件内定义状态 const [pou2, setPou2] = useState(/* 初始状态值 */) // 触发状态更新 const handleImgIdUpdate = () => { setPou2({ ...pou2, imgId: po?.imgId2 }) } // 监听pou2变化,执行更新后的逻辑 useEffect(() => { // 此处拿到的pou2已经是更新完成的最新值 // 原计划写在setState回调里的逻辑直接放在这里即可 console.log('pou2更新完成', pou2) }, [pou2])
如果组件中有多处修改
pou2的逻辑,不需要每次更新都触发回调,可以搭配useRef做触发标记,只在指定更新场景下执行回调:const isImgIdUpdate = useRef(false) const handleImgIdUpdate = () => { isImgIdUpdate.current = true setPou2({ ...pou2, imgId: po?.imgId2 }) } useEffect(() => { if (!isImgIdUpdate.current) return isImgIdUpdate.current = false // 仅imgId触发的pou2更新会执行这里的逻辑 }, [pou2])
方案2:封装支持回调的自定义状态Hook
如果项目中有大量这类状态更新后执行回调的需求,可以封装通用自定义Hook,使用体验和类组件setState完全一致:
import { useState, useRef, useEffect, useCallback } from 'react' function useCallbackState(initialValue) { const [state, setState] = useState(initialValue) const callbackRef = useRef(null) const setCustomState = useCallback((newState, callback) => { callbackRef.current = callback setState(newState) }, []) useEffect(() => { if (callbackRef.current) { callbackRef.current(state) callbackRef.current = null } }, [state]) return [state, setCustomState] } // 组件内使用 const [pou2, setPou2] = useCallbackState(/* 初始值 */) // 直接传入第二个回调参数即可,不会触发类型报错 setPou2({ ...pou2, imgId: po?.imgId2 }, () => { // 状态更新完成后执行的逻辑 })
内容的提问来源于stack exchange,提问作者János
相关产品推荐
相关产品推荐

