上面的代码实现了一个繁难的登录性能(为了缩小代码量,去掉了明码)。
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;