上面的代码实现了一个繁难的登录性能(为了缩小代码量,去掉了明码)。
import React, { useState } from 'react';
const api = {
login(username) {
console.log('username', username);
},
};
function Login() {
const [username, setUsername] = useState('');
const onSubmit = () => {
if (!username) {
alert('Please input username');
return;
}
api.login(username,);
};
return (
<div>
<h1>Login</h1>
<input
type="text"
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
<button onClick={onSubmit}>submit</button>
</div>
);
}
export default Login;
当初咱们要减少一个需要:
监听页面上的回车事件,而后发动登录,代码如下:
useEffect(() => {
const onKeyup = (e) => {
if (e.key === 'Enter') {
onSubmit();
}
}
window.addEventListener('keyup', onKeyup);
}, []);
代码看起来没问题,但运行一下,咱们就会发现并没有依照预期倒退,在输入框曾经输出用户名的前提下,页面上还是会始终提醒让咱们输出用户名。
什么起因?
问题出在onKeyup
外部的onSubmit
,因为onSubmit
所在的useEffect
没有依赖,所以只会在初始化执行一次,onSubmit
外部的username
也就会始终处于首次渲染的状态,值为空字符。
如何解决?
将onSubmit
退出useEffect
的依赖中。
useEffect(() => {
const onKeyup = (e) => {
if (e.key === 'Enter') {
onSubmit();
}
}
window.addEventListener('keyup', onKeyup);
}, [onSubmit]);
依赖加好了,然而看着下面的代码,咱们又会发现一个问题,因为react
会在每次渲染的时候从新创立组件内非hooks
的值,这就导致了每次渲染的onSubmit
的值产生扭转,进而导致监听onSubmit
的useEffect反复执行。
如何解决?
给onSubmit
加上useCallback
,将username
退出到useCallback
的依赖中。
const onSubmit = useCallback(() => {
if (!username) {
alert('Please input username');
return;
}
login(username);
}, [username]);
这样,在每次组件渲染时,只有当username
的值产生扭转,onSubmit
的值才会跟着产生扭转,从而解决了useEffect
重复执行的问题。
咱们再运行一下,又有新问题了!
当咱们输出的username
长度超过1
时,会发现login
接口被调用了屡次。
什么起因?
问题来到了useCallbak
,每次username
发生变化的时候,onSubmit
都会被更新,从而导致useEffect
为每次username
的扭转都执行了一次,也就屡次绑定了onKeyup
了,后果是屡次调用onSubmit
。
怎么解决?
利用useEffect
的cleanup
。
在cleanup
外面解绑onKeyup
。这样就不会存在屡次绑定的onKeyup
被执行的状况了,只会存在一个最新的onKeyup
绑定。
useEffect(() => {
const onKeyup = (e) => {
if (e.key === 'Enter') {
onSubmit();
}
}
window.addEventListener('keyup', onKeyup);
return () => {
window.removeEventListener('keyup', onKeyup);
}
}, [onSubmit]);
至此,代码工作的完整。
残缺的代码如下:
import React, { useState, useEffect, useCallback } from 'react';
const login = (username) => {
console.log('username', username);
};
function Login() {
const [username, setUsername] = useState('');
const onSubmit = useCallback(() => {
if (!username) {
alert('Please input username');
return;
}
login(username);
}, [username]);
useEffect(() => {
const onKeyup = (e) => {
if (e.key === 'Enter') {
onSubmit();
}
}
window.addEventListener('keyup', onKeyup);
return () => {
window.removeEventListener('keyup', onKeyup);
}
}, [onSubmit]);
return (
<div>
<h1>Login</h1>
<input
type="text"
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
<button onClick={onSubmit}>submit</button>
</div>
);
}
export default Login;
发表回复