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

React-Form输入时组件持续重渲染、输入内容自动重置问题如何修复?

问题修复方案

问题根因

  • 你在组件的同步渲染逻辑中直接调用了setPayload,每次组件渲染时只要props.payload不为空就会触发state更新,进而触发无限重渲染,导致输入框内容被重置
  • 你将LoginWindow定义为Auth组件内部的子组件,每次Auth重渲染时都会生成一个全新的LoginWindow组件实例,原Modal会被直接卸载再挂载,输入的内容自然会被清空
  • 输入框作为受控组件没有绑定value属性与state关联,重渲染后输入内容无法和state同步
  • 未做缓存的对象、函数每次渲染都会生成新的引用,也会加重不必要的重渲染

修复步骤

  1. 移除渲染逻辑中的同步setPayload调用,改用useEffect监听props.payload变化后再更新本地state
  2. 不要在组件内部定义子组件,直接把Modal的JSX写在Auth的return中,或者将LoginWindow抽到组件外部,通过props传递依赖参数
  3. 给受控输入框加上value属性绑定对应的state
  4. 对需要作为依赖传递的对象、函数用useMemo、useCallback做缓存,避免不必要的重渲染

修复后参考代码

import React, {useState, useEffect, useCallback, useMemo} from 'react';
import useApi, {IPayload} from './hooks/useApi';
import Modal from 'react-modal'
import './modal.css';
Modal.setAppElement('#root')

interface IProps {
  payload:IPayload|null,
  closeAction?:()=>void,
}

const defaultProps:IProps = {
  payload:null,
  closeAction: ()=>null,
}

function Auth(props:IProps):JSX.Element{
  const [auth, updateAuth] = useState<boolean>(false)
  const [authModalIsOpen, setAuthModal] = useState(true)
  const [username, setUsername] = useState('')
  const [password, setPassword] = useState('')

  // 用useCallback缓存函数,避免每次渲染生成新引用
  const forceLogin = useCallback(()=>{
    setAuthModal(true)
    updateAuth(false)
  }, [])

  const closeAuthModal = useCallback(()=>{
    if(auth){ setAuthModal(false) }
  }, [auth])

  const loginAction = useCallback((res:any)=>{
    updateAuth(true)
    setAuthModal(false)
    setUsername(res.auth)
  }, [])

  // 用useMemo缓存对象,避免每次渲染生成新引用
  const opts = useMemo(()=>({
    username: username,
    password: password,
    fail: forceLogin,
  }), [username, password, forceLogin])

  const defaultPayload = useMemo(():IPayload => ({
      path:'notes/validateAuth/',
      method: 'GET',
      body: null,
      callback: loginAction
  }), [loginAction])

  const [payload, setPayload] = useState(defaultPayload)
  // 改用useEffect监听props.payload变化,避免渲染期间同步更新state
  useEffect(()=>{
    if(props.payload!==null){
      setPayload(props.payload)
    }
  }, [props.payload])

  const SubmitLogin = useCallback(()=>{
    setPayload(defaultPayload)
  }, [defaultPayload])

  // 直接返回Modal JSX,不要在内部定义子组件避免重复卸载挂载
  return(
    <Modal
      isOpen={authModalIsOpen}
      onRequestClose={closeAuthModal}
      className='SearchModal'
      overlayClassName='SearchOverlay'
      >
      <div className="IoLinks_wrapper">
        <div className="IoLinks_incoming">
          <form onSubmit={(e)=>{
            e.preventDefault()
            SubmitLogin()
          }}>
            {/* 给输入框加上value属性绑定state */}
            <input 
              name='username' 
              className='greenput_narrow' 
              value={username}
              onChange={(e)=>setUsername(e.target.value)}
            /><br />
            <input 
              type="password" 
              name='password' 
              className='greenput_narrow' 
              value={password}
              onChange={(e)=>setPassword(e.target.value)}
            /><br />
            <button className='greenput_narrow' type="submit">Login</button>
          </form>
        </div>
        <div className="IoLinks_outgoing">
          <h1>NullDisk</h1>
          <ul>
            <li>Military Grade Encryption</li>
            <li>Zettelkasten Schema</li>
            <li>VIM Keybindings</li>
          </ul>
        </div>
      </div>
    </Modal>
  )
}

Auth.defaultProps = defaultProps
export default Auth;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 11:00:00