React组件中绑定的登录函数为何每次输入都会自动触发?
问题成因
你在为按钮绑定onClick事件时,直接写入了loginRequest(username, password)这个函数调用表达式,而非待触发的函数引用。
React组件每次执行渲染(包含首次挂载渲染、state更新触发的重渲染)时,都会先计算JSX中所有属性的表达式值:这行函数调用会在渲染阶段直接执行,拿到返回值后再绑定给onClick属性,完全不会等待用户点击按钮后再触发。
- 页面首次加载时组件完成第一次渲染,直接触发一次登录请求
- 输入框输入内容会更新对应state,触发组件重渲染,每重渲染一次就会执行一次函数调用,最终出现逐字符发送登录请求的现象
另外你代码中密码输入框的type属性设置为了text,输入内容会明文展示,属于配套的易用性问题。
修复方案
有两种符合React事件绑定规范的写法,可以实现仅点击按钮时才触发请求的效果:
写法1:箭头函数包裹调用逻辑
在onClick属性中传入一个箭头函数作为事件回调,将登录请求的调用逻辑放在箭头函数内部,只有点击事件触发时才会执行内部代码:
<Button onClick={() => loginRequest(username, password)} className='withdraw-deposit-button' > Login/Deposit </Button>
同时将密码输入框的type属性修正为password,隐藏输入的明文内容:
<input type="password" placeholder="Password" onChange={e => changePassword(e.target.value)} value={password} />
写法2:直接读取组件内state,传递函数引用
修改loginRequest函数逻辑,不需要通过参数传递账号密码,直接读取组件作用域内的username和password状态值,绑定事件时直接传入函数引用(不要加括号执行)即可,这种写法不需要每次渲染都创建新的箭头函数,性能更优:
const loginRequest = async () => { // 直接读取组件内的state,无需额外传参 const response = await service.loginRequest(username, password); console.log(response); } // 绑定事件时直接传入函数名 <Button onClick={loginRequest} className='withdraw-deposit-button' > Login/Deposit </Button>
修正后完整代码
import { useState } from 'react'; // 需根据项目实际路径引入Card、Button组件与service请求模块 function LoginPage() { const [username, changeUsername] = useState(''); const [password, changePassword] = useState(''); const loginRequest = async () => { const response = await service.loginRequest(username, password); console.log(response); } return ( <Card hoverable className='transaction-button-card'> <h1>Enter username and password</h1> <input type="text" placeholder="Username" onChange={e => changeUsername(e.target.value)} value={username} /> <input type="password" placeholder="Password" onChange={e => changePassword(e.target.value)} value={password} /> <Button onClick={loginRequest} className='withdraw-deposit-button' > Login/Deposit </Button> </Card> ); } export default LoginPage;
内容的提问来源于stack exchange,提问作者abidinberkay
相关产品推荐
相关产品推荐

