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

React中处理input和textarea的onFocus、onBlur事件时聚焦状态异常如何解决

问题根因

切换焦点时的事件触发顺序导致了状态空档:从textarea切换到input的过程中,textarea的onBlur会先执行,直接把contentFocused设为false,此时input的onFocus还没触发,两个状态同时为false,UI就会出现临时收缩的情况。

修复方案

方案1:最小改动修复原有逻辑

给失焦逻辑加短延时,预留出焦点切换的时间,避免误判状态:

import { useState, useRef } from 'react';

// 初始化状态改为布尔值false,更符合逻辑
const [titleFocused, setTitleFocus] = useState(false);
const [contentFocused, setContentFocus] = useState(false);
// 存储延时任务id
const blurTimer = useRef(null);

function handleFocus(event) {
  // 聚焦时先清空未执行的失焦任务,说明是表单内切换,不需要收缩
  if (blurTimer.current) {
    clearTimeout(blurTimer.current);
    blurTimer.current = null;
  }
  const {name} = event.target;
  name === 'title' && setTitleFocus(true);
  name === 'content' && setContentFocus(true);
}

function handleUnfocus(event) {
  const {name} = event.target;
  // 延时100ms再修改状态,确认没有新的聚焦动作再收缩
  blurTimer.current = setTimeout(() => {
    name === 'title' && setTitleFocus(false);
    name === 'content' && setContentFocus(false);
  }, 100);
}

return (
  <div >
    <form className="create-note">
      {/* 注意原逻辑缺少括号,运算符优先级可能导致判断错误,这里补加括号 */}
      {(titleFocused || contentFocused) && (
        <input
          name="title"
          onChange={handleChange}
          value={note.title}
          placeholder="Title"
          onFocus={handleFocus}
          onBlur={handleUnfocus}
        />
      )}
      <textarea
        name="content"
        onChange={handleChange}
        value={note.content}
        placeholder="Take a note..."
        onFocus={handleFocus}
        onBlur={handleUnfocus}
        rows={titleFocused || contentFocused ? "3" : "1"}
      />
      <Zoom in={titleFocused || contentFocused} appear={true}>
        <Fab onClick={submitNote}>
          <AddIcon fontSize="large" />
        </Fab>
      </Zoom>
    </form>
  </div>
);

方案2:更简洁的全局表单状态方案

不需要维护两个独立的输入框聚焦状态,直接监听整个表单的聚焦/失焦事件即可:只有焦点完全离开表单时才触发收缩,表单内部切换焦点不会触发表单失焦,从根源避免了空档问题,代码也更精简:

import { useState } from 'react';

const [formFocused, setFormFocused] = useState(false);

return (
  <div >
    <form 
      className="create-note"
      onFocus={() => setFormFocused(true)}
      onBlur={() => setFormFocused(false)}
    >
      {formFocused && (
        <input
          name="title"
          onChange={handleChange}
          value={note.title}
          placeholder="Title"
        />
      )}
      <textarea
        name="content"
        onChange={handleChange}
        value={note.content}
        placeholder="Take a note..."
        rows={formFocused ? "3" : "1"}
      />
      <Zoom in={formFocused} appear={true}>
        <Fab onClick={submitNote}>
          <AddIcon fontSize="large" />
        </Fab>
      </Zoom>
    </form>
  </div>
);

内容的提问来源于stack exchange,提问作者Vladd Cantor

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 14:45:10