[ 筆記 ] debounce 的用法


Posted by Akira on 2023-03-16

這次在寫input search的功能時,使用者輸入的內容,會逐字去打API搜尋,如果每打一個字,API就要搜尋一次,會造成很大的效能問題,加上我這次搭配vue-infinite-loading,直接讓vue-infinite-loading進到一個endless loop,讓瀏覽器當機。

<template>
<input :value=value @input="inputChange"
</template>

<script>
data(){
    return{
        value: "",
    }
},
method:{
    inputChange(value) {
      console.log(value)
    },
}
</script>

每打一個字就會console一次,我想到等使用者一次打了很多字,之後等了幾秒,不再輸入了才執行function,這次是用lodash這套件的功能,直接輕鬆做debounce

Vue

<template>
<input :value=value @input="inputChange"
</template>

<script>
const _ = require("lodash");
export default {
    data(){
        return{
            value: "",
        }
    },
    method:{
        inputChange(value) {
          this.onSearch(value);
        },
        onSearch: _.debounce(function () {
        console.log(value)
        }, 500),
    }
}
</script>

這邊設定間隔0.5秒使用者沒有繼續輸入,才會console出value。

react

剛好也看到react設計debounce的作法,也順道記錄下來。

import React, { useState, useEffect, useReducer } from 'react';

import Card from '../UI/Card/Card';
import classes from './Login.module.css';
import Button from '../UI/Button/Button';

const emailReducer = (state, action)=>{
  if(action.type === "USER_INPUT") {
    return {value:action.val, isValid: action.val.includes('@')}
  }
  if(action.type === "INPUT_BLUR") {
    return {value: state.value, isValid: state.value.includes('@')}
  }
  return {value:'', isValid: false}
}
const passwordReducer = (state, action)=>{
  if(action.type === "USER_INPUT") {
    return {value:action.val, isValid: action.val.trim().length > 6}
  }
  if(action.type === "INPUT_BLUR") {
    return {value: state.value, isValid: state.value.trim().length > 6}
  }
  return {value:'', isValid: false}
}
const Login = (props) => {
  // const [enteredEmail, setEnteredEmail] = useState('');
  // const [emailIsValid, setEmailIsValid] = useState();
  // const [enteredPassword, setEnteredPassword] = useState('');
  // const [passwordIsValid, setPasswordIsValid] = useState();
  const [formIsValid, setFormIsValid] = useState(false);

  const [emailState, dispatchEmail] = useReducer(emailReducer,{
    value:'', 
    isValid: null
  })
  const [passwordState, dispatchPassword] = useReducer(passwordReducer,{
    value:'', 
    isValid: null
  })
  const {isValid: emailIsValid} = emailState
  const {isValid: passwordIsValid} = passwordState

  useEffect(()=>{
    const identifier = setTimeout(()=>{
      console.log('checking')
      setFormIsValid(
        emailIsValid && passwordIsValid
      );
    }, 500)
    return ()=>{
      console.log('CLEANUP')
      clearTimeout(identifier)
    }
  },[emailIsValid, passwordIsValid])

  const emailChangeHandler = (event) => {
    dispatchEmail({type:'USER_INPUT', val:event.target.value})
    // setEnteredEmail(event.target.value);

  };

  const passwordChangeHandler = (event) => {
    dispatchPassword({type:'USER_INPUT', val:event.target.value})
    setFormIsValid(
      emailState.isValid && passwordState.isValid
    );
  };

  const validateEmailHandler = () => {
    dispatchEmail({type:'INPUT_BLUR'})
    // setEmailIsValid(emailState.isValid);
  };

  const validatePasswordHandler = () => {
    dispatchPassword({type:'INPUT_BLUR'})
  };

  const submitHandler = (event) => {
    event.preventDefault();
    props.onLogin(emailState.value, passwordState.value);
  };

  return (
    <Card className={classes.login}>
      <form onSubmit={submitHandler}>
        <div
          className={`${classes.control} ${
            emailState.isValid === false ? classes.invalid : ''
          }`}
        >
          <label htmlFor="email">E-Mail</label>
          <input
            type="email"
            id="email"
            value={emailState.value}
            onChange={emailChangeHandler}
            onBlur={validateEmailHandler}
          />
        </div>
        <div
          className={`${classes.control} ${
            passwordState.isValid === false ? classes.invalid : ''
          }`}
        >
          <label htmlFor="password">Password</label>
          <input
            type="password"
            id="password"
            value={passwordState.value}
            onChange={passwordChangeHandler}
            onBlur={validatePasswordHandler}
          />
        </div>
        <div className={classes.actions}>
          <Button type="submit" className={classes.btn} disabled={!formIsValid}>
            Login
          </Button>
        </div>
      </form>
    </Card>
  );
};

export default Login;

#debounce #Vue #React







Related Posts

什麼是 API? SOAP? 其他 HTTP API?

什麼是 API? SOAP? 其他 HTTP API?

初探 DNS 系統

初探 DNS 系統

IIS 和 ASP.NET Core 將網站強制導向HTTPS並且使用HTTP狀態碼為301

IIS 和 ASP.NET Core 將網站強制導向HTTPS並且使用HTTP狀態碼為301


Comments