上面的代码实现了一个繁难的登录性能(为了缩小代码量,去掉了明码)。

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

怎么解决?
利用useEffectcleanup
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;