You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中如何使用useEffect和useCallback触发state hook重新渲染?

问题根源

你遇到的点击两次才触发请求的核心原因是React状态更新的异步特性:在同一个事件处理函数的执行上下文里,调用setState后不会立刻修改当前作用域下的状态变量,状态更新会被批量推入队列,等到当前事件回调执行完毕后才会触发重渲染,重渲染后才能拿到最新的状态值。
你在submit函数里刚调用setKeyValid(true),紧接着判断if (keyValid === true),此时拿到的keyValid还是本次渲染初始的旧值(false),所以判断条件不生效,只有第二次点击的时候,keyValid已经是上一次渲染更新后的true,才会走数据库请求的逻辑。你之前看到useEffect里打印的keyValid是更新后的值,是因为useEffect会在重渲染完成后执行,此时状态已经更新完成,属于React的正常执行时序。

另外你的代码还存在几个可优化的问题:

  • 冗余的useCallback封装,且依赖项配置错误:updateKeyValid完全没有存在的必要,直接调用setKeyValid即可
  • 长度校验逻辑写反:!inputKeyRef.current.value.length < 12的运算优先级不符合校验需求,无法正确判断长度范围
  • 混用ref和状态读取输入值,没有必要,表单输入直接绑定状态更符合React开发规范
  • Button组件的onClick属性多写了一个闭合大括号,属于语法错误

解决方案

方案1:直接在验证通过后发起请求(最简实现)

不需要等keyValid状态更新,校验通过后直接执行数据库请求逻辑,同时更新状态即可:

import { useState } from 'react'

export function Form() {
    const[inputKey, setInputKey] = useState("");
    const [keyValid, setKeyValid] = useState(false);
    const [keyAuthentic, setKeyAuthentic] = useState(false);

    // 输入框绑定onChange更新状态,你原代码缺少这部分
    const handleInputChange = (e) => {
        setInputKey(e.target.value);
    }

    const submit = e => {
        e.preventDefault();
        // 修正长度校验逻辑:要求密钥长度在12-20位之间
        const keyLength = inputKey.length;
        const isValid = keyLength >= 12 && keyLength <= 20;
        setKeyValid(isValid);
        
        if (isValid) {
            // 校验通过直接发请求,不用等待状态更新
            db.collection("users").doc(inputKey).get().then((doc) => {
                if (doc.exists) {
                    setKeyAuthentic(true)
                    console.log(doc.data())
                }
            });
        }
    };

    return (
        <div>
            {/* 输入框绑定状态 */}
            <input value={inputKey} onChange={handleInputChange} />
            <div className="form__submit">
                <Button type="submit" onClick={submit}>Submit</Button>
            </div>
        </div>
    )
}

export default Form

方案2:通过useEffect监听状态触发请求

如果你的业务逻辑要求必须等keyValid状态更新后再触发请求,就把数据库请求逻辑放到useEffect中,监听keyValid变化自动执行:

import { useState, useEffect } from 'react'

export function Form() {
    const[inputKey, setInputKey] = useState("");
    const [keyValid, setKeyValid] = useState(false);
    const [keyAuthentic, setKeyAuthentic] = useState(false);

    const handleInputChange = (e) => {
        setInputKey(e.target.value);
    }

    // 监听keyValid变化,状态更新后自动发起请求
    useEffect(() => {
        if (keyValid) {
            db.collection("users").doc(inputKey).get().then((doc) => {
                if (doc.exists) {
                    setKeyAuthentic(true)
                    console.log(doc.data())
                }
            });
        }
    }, [keyValid, inputKey]) // 依赖项加入keyValid和inputKey,确保拿到最新值

    const submit = e => {
        e.preventDefault();
        const keyLength = inputKey.length;
        const isValid = keyLength >= 12 && keyLength <= 20;
        setKeyValid(isValid);
    };

    return (
        <div>
            <input value={inputKey} onChange={handleInputChange} />
            <div className="form__submit">
                <Button type="submit" onClick={submit}>Submit</Button>
            </div>
        </div>
    )
}

export default Form

内容的提问来源于stack exchange,提问作者Levan Marston

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 00:57:03