欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

React之防止按鈕多次點(diǎn)擊事件?重復(fù)提交

 更新時(shí)間:2023年10月23日 11:01:38   作者:Zeng__Y1  
這篇文章主要介紹了React之防止按鈕多次點(diǎn)擊事件?重復(fù)提交問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

React防止按鈕多次點(diǎn)擊事件 重復(fù)提交

為了方便,簡單的記錄一下:

在state中設(shè)置一個(gè)控制點(diǎn)擊事件

this.state = {

isClick: true

}

在點(diǎn)擊事件的函數(shù)里

handleOk = () => {

const { isClick } = this.state

if (isClick) {   //如果為true 開始執(zhí)行

this.setState({ isClick: false })   //將isClick 變成false,將不會執(zhí)行處理事件

// 編寫點(diǎn)擊事件執(zhí)行的代碼

const that = this   // 為定時(shí)器中的setState綁定this

setTimeout(function () {       // 設(shè)置延遲事件,1秒后將執(zhí)行

that.setState({ isClick: true })   // 將isClick設(shè)置為true

}, 1000);

}

};

防止提交按鈕重復(fù)點(diǎn)擊的實(shí)踐

防止按鈕重復(fù)點(diǎn)擊

按鈕是前端界面中承接著用戶操作的很重要的一個(gè)環(huán)節(jié),前端界面用戶和系統(tǒng)的交互都通過按鈕來完成,與系統(tǒng)的交互自然就少不了把用戶的意向保存到系統(tǒng)中,如今面對前后端分離的部署方案,前端與后端的通信都是通過接口來完成的。

那么問題就來了發(fā)送一個(gè)接口就需要等待,那么等待的這段時(shí)間可長可短(根據(jù)用戶當(dāng)前的網(wǎng)絡(luò)時(shí)間決定的),如果一個(gè)請求三秒以后才回來,用戶在這一段時(shí)間再次點(diǎn)擊怎么辦。

在如今這個(gè)網(wǎng)速很快的時(shí)代,可能延遲是非常低的,所以給用戶考慮的時(shí)間并不多,但是如果請求時(shí)間長重復(fù)點(diǎn)擊就需要做限制了。

本次就是基于項(xiàng)目中的發(fā)送請求的按鈕做防止重復(fù)點(diǎn)擊的一些探索。

現(xiàn)在的前端的項(xiàng)目中發(fā)送請求大都采用 async/await 的語法糖吧異步請求封裝,正是因?yàn)槭钱惒秸埱?,回調(diào)之前的按鈕都是不應(yīng)該點(diǎn)擊的,這樣可以防止一些請求二次發(fā)送造成的一些bug。

舉一個(gè)簡單的例子,在項(xiàng)目中有一個(gè)按鈕是提交按鈕,把用戶的的一些信息通過調(diào)用接口的形式發(fā)送給后端,然后跳轉(zhuǎn)到詳情頁面,這就是一個(gè)很簡單的前端交互的場景。我們來簡單實(shí)現(xiàn)一下(基于React實(shí)現(xiàn)方式)

const ButtonClick: React.FC = () => {
    const [value, setValue] = useState('');
    const copyValue = useRef('');
    const sendValue = (name: string): Promise<string> =>
        new Promise((resolve: Function, reject: Function) => {
            setTimeout(() => {
                if (!name) {
                    return reject('請輸入對應(yīng)對容')
                }
                copyValue.current = name;
                resolve('success');
            }, 3000)
        })
    const getValue = async () => {
        try {
            const flag = await sendValue(value);
            console.log(flag);
            console.log(copyValue.current);
            console.log('其他業(yè)務(wù)操作')
        } catch (error) {
            message.warning(error)
            console.log(error)
        }
    }
    const inputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
        setValue(event.target.value)
    }
    return (
        <>
            <Input onChange={inputChange} value={value} style = {{width: "300px"}}></Input>
            <Button onClick={getValue} type = "primary" style = {{marginTop: "20px"}}>發(fā)送</Button>
        </>
    )
}

上面的代碼就是簡單把用戶輸入的內(nèi)容給持久化起來,這里借用了setTimeout來模仿網(wǎng)絡(luò)延遲的效果,如果在請求處理過程中不對重復(fù)點(diǎn)擊進(jìn)行控制,那么就會出現(xiàn)下面的情況,連續(xù)發(fā)送好幾次請求,最終效果差強(qiáng)人意。

所以針對這個(gè)按鈕就需要做重復(fù)點(diǎn)擊控制,每次請求成功的時(shí)候才能恢復(fù)按鈕的可點(diǎn)擊狀態(tài)。

那么簡單的實(shí)現(xiàn)代碼就來了針對按鈕點(diǎn)擊的方法:

const [affectLoading,setAffectLoading] = useState(false);
const getValue = async () => {
        if(affectLoading) {
            return;
        }
        setAffectLoading(true);
        try {
            const flag = await sendValue(value).finally(() =>{
                setAffectLoading(false)
            })
            console.log(flag);
            console.log(copyValue.current);
            console.log('其他業(yè)務(wù)操作')
        } catch (error) {
            message.warning(error)
            console.log(error)
        }
    }

上面的方式針對按鈕事件單獨(dú)定義了一個(gè)變量進(jìn)行了控制,每次都是請求完畢的時(shí)候把控制變量給置為false,上面這種方式確實(shí)是可行的但是如果針對每一個(gè)按鈕事件都需要單獨(dú)定義一個(gè)變量,會造成內(nèi)部的變量很多后期很難維護(hù)。那么就像節(jié)流一樣能不能針對這種情況抽離出一個(gè)公共的方法來實(shí)現(xiàn)呢。

經(jīng)過梳理,如果我們抽離出一個(gè)方法,和這種單獨(dú)的寫法是一致的,首先定義一個(gè)變量置為false,然后進(jìn)行第一次請求,這個(gè)時(shí)候給變量置為true,等待請求結(jié)束再給變量置為false,這樣就達(dá)到了控制重復(fù)點(diǎn)擊的效果。前幾天解除了js的裝飾器,首先想到的就是使用裝飾器在代碼編譯的時(shí)候給注入這一過程??梢詫τ赗eact Hook 是沒有類這一個(gè)概念的。所以對于裝飾器也用不了(但是對于React的class組件還是可以使用的。

下面會給出實(shí)現(xiàn)方式)。對于React Hook則可以使用高階函數(shù)的方式實(shí)現(xiàn),傳入一個(gè)方法,返回包裝過的方法,高階函數(shù)類似與下面的方式:

const demo = () => {
        console.log('處理業(yè)務(wù)邏輯');
    }
    const warpButton = (buttonEvent:Function) => {
       return () => {
        console.log('begin');
        buttonEvent();
        console.log('end');
       }
    }
    HTML:
    <Button onClick={warpButton(demo)}>發(fā)送</Button>

經(jīng)過warpButton的包裝可以給注入的方法執(zhí)行一個(gè)額外的邏輯,那么我們實(shí)現(xiàn)的邏輯也就可以基于次來實(shí)現(xiàn)了。

下面是代碼:

const getValue = async () => {
        try {
            const flag = await sendValue(value)
            console.log(flag);
            console.log(copyValue.current);
            console.log('其他業(yè)務(wù)操作')
        } catch (error) {
            message.warning(error)
            console.log(error)
        }
    }
    const wrapButton = (buttonEvent: Function, messageValue?: string) => {
        let flag = false;
        return async function () {
            if (flag) {
                messageValue && message.warning(messageValue);
                return;
            }
            flag = true;
            //@ts-ignore
            await buttonEvent.apply(this, arguments).finally(() => {
                flag = false;
            })
        }
    }
    
    HTML:
    <Button onClick={wrapButton(getValue,'loading')} type="primary" style={{ marginTop: "20px" }}>發(fā)送</Button>

通過這個(gè)高階函數(shù)可以自動幫助我們在執(zhí)行請求的時(shí)候控制對應(yīng)的請求狀態(tài),這樣就能夠做到自動對我們注入的函數(shù)進(jìn)行控制。同時(shí)可以根據(jù)傳入的提示信息進(jìn)行提示。

對于公共方法還需要在考慮一下兼容性,如果這里傳入的就是一個(gè)普通的js方法這樣就報(bào)錯(cuò)了,所以需要對傳入的方法進(jìn)行判斷,增加兼容性:

代碼如下

    const wrapButton = (buttonEvent: Function, messageValue?: string) => {
        let flag = false;
        return async function () {
            if (flag) {
                messageValue && message.warning(messageValue);
                return;
            }
            flag = true;
            if (buttonEvent.constructor.name === 'AsyncFunction') {
                //@ts-ignore
                await buttonEvent.apply(this, arguments).finally(() => {
                    flag = false
                })
            } else {
                //@ts-ignore
                buttonEvent.apply(this, arguments);
                flag = false;
            }
        }
    }

對與React Hook 中可以使用高階函數(shù)的方式可以實(shí)現(xiàn),對于之前的class 組件則是可以使用裝飾器了,不僅看上去美觀同時(shí)使用起來也是比較方便。

但是裝飾器只能用于類和類的屬性上,不能用于方法上,因?yàn)榇嬖诤瘮?shù)提升。

直接給出裝飾器代碼:

const lockButton = (value: string = 'loading') => {
    return (target?: any, key?: any, desc?: any) => {
        const fn = desc.value;
        let flag = false;
        desc.value = async function () {
            if (flag) {
                message.warning(value);
                return;
            }
            flag = true;
            console.log(fn.constructor.name === 'AsyncFunction');
            if (fn.constructor.name === 'AsyncFunction') {
                //@ts-ignore
                await fn.apply(this, arguments).finally(() => {
                    flag = false;
                })
            } else {
                fn.apply(this, arguments);
                flag = false;
            }

            return target;
        }
    }
}

在class組件中的使用:

    class ChekcButton1 extends Component<{}, {}> {
    constructor(props: {}) {
        super(props)
        this.state = {

        }
    }
    private getData = (timer: number): Promise<Number> =>
    new Promise((resolve) => {
        setTimeout(() => {
            resolve(timer);
        }, timer)
    })
    @lockButton('異步buttton請求中')
    async getValue1() {
        const value = await this.getData(5000);
        console.log(value);
        if (value > 500) {
            console.log('判斷');
        }
    }
    render() {
        return (
            <>
                <div>
                    測試class組件的button裝飾器:
                    <div>
                        <Button onClick={this.getValue1.bind(this)} type="primary">測試button</Button>
                    </div>
                </div>
            </>
        )
    }
}

總結(jié)了以上兩種方式不管使用裝飾器或者是高階函數(shù)的方式都可以做到對按鈕的點(diǎn)擊進(jìn)行控制,但是究其根本還是通過定義變量控制的,所以自己也可以在其他框架中進(jìn)行探索。

在vue中的嘗試:同樣繪制一個(gè)基礎(chǔ)的頁面一個(gè)按鈕一個(gè)輸入框模擬發(fā)送請求:

<template>
  <div id="app">
    <el-input v-model="input" placeholder="請輸入內(nèi)容" class="inputVDom"></el-input>
    <el-button type="primary" @click="getValue">按鈕</el-button>
  </div>
</template>

<script>
import { buttonLock } from "../../util/util";
export default {
  name: "buttonLock",
  data() {
    return {
      input: "",
      copyValue: "",
    };
  },
  methods: {
    getData: function (value) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          if (!value) {
            this.$message({
              message: "'this needs some value!'",
              type: "warning",
            });
            reject("this needs some Value!");
            return;
          }
          this.copyValue = value;
          resolve("success");
        }, 3000);
      });
    },
    getValue: async function() {
      try {
        const value = await this.getData(this.input);
        console.log(value);
        console.log(this.input)
      }catch(error) {
        console.log(error); 
      }
    },
  },
};
</script>

同樣的情況出現(xiàn)了,請求返回之前重復(fù)點(diǎn)擊就會重復(fù)執(zhí)行。

同樣的方法使用高階函數(shù)給他包裝起來。

//utils類中方法
const buttonLock = (buttonEvent) => {
    let flag = false;
    console.log(buttonEvent)
    return async function() {
        if(flag) {
            console.log('loading')
            return;
        }
        flag = true;
        await buttonEvent.apply(this,arguments).finally(() => {
            flag = false;
        })
    }
}
//使用:
methods:{
    getValue: buttonLock(async function() {
    try {
        const value = await this.getData(this.input);
        console.log(value);
        console.log(this.input)
      }catch(error) {
        console.log(error); 
      }
})
} 

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 深入理解React高階組件

    深入理解React高階組件

    本篇文章主要介紹了深入理解React高階組件,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-09-09
  • react-redux action傳參及多個(gè)state處理的實(shí)現(xiàn)

    react-redux action傳參及多個(gè)state處理的實(shí)現(xiàn)

    本文主要介紹了react-redux action傳參及多個(gè)state處理的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • React項(xiàng)目配置axios和反向代理和process.env環(huán)境配置等問題

    React項(xiàng)目配置axios和反向代理和process.env環(huán)境配置等問題

    這篇文章主要介紹了React項(xiàng)目配置axios和反向代理和process.env環(huán)境配置等問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • 如何在React項(xiàng)目中使用AntDesign

    如何在React項(xiàng)目中使用AntDesign

    我們在后臺管理系統(tǒng)React項(xiàng)目開發(fā)中會有Table表格、Form表單、List列表、Button按鈕等組件,這個(gè)時(shí)候我們可以使用AntDesign來減少開發(fā)中不必要的樣式問題,本文就介紹了eact項(xiàng)目中使用AntDesign,感興趣的可以了解一下
    2022-04-04
  • React?Native?加載H5頁面的實(shí)現(xiàn)方法

    React?Native?加載H5頁面的實(shí)現(xiàn)方法

    這篇文章主要介紹了React?Native?加載H5頁面的實(shí)現(xiàn)方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-04-04
  • react結(jié)合typescript?封裝組件實(shí)例詳解

    react結(jié)合typescript?封裝組件實(shí)例詳解

    這篇文章主要為大家介紹了react結(jié)合typescript?封裝組件實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • React前端DOM常見Hook封裝示例上

    React前端DOM常見Hook封裝示例上

    這篇文章主要為大家介紹了React前端DOM常見Hook封裝示例上篇,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-07-07
  • Jira 任務(wù)管理系統(tǒng)項(xiàng)目總結(jié)講解

    Jira 任務(wù)管理系統(tǒng)項(xiàng)目總結(jié)講解

    這篇文章主要為大家介紹了Jira 任務(wù)管理系統(tǒng)項(xiàng)目總結(jié)講解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • 用React-Native+Mobx做一個(gè)迷你水果商城APP(附源碼)

    用React-Native+Mobx做一個(gè)迷你水果商城APP(附源碼)

    這篇文章主要介紹了用React-Native+Mobx做一個(gè)迷你水果商城APP,功能需要的朋友可以參考下
    2017-12-12
  • vue3中獲取ref元素的幾種方式總結(jié)

    vue3中獲取ref元素的幾種方式總結(jié)

    這篇文章主要介紹了vue3中獲取ref元素的幾種方式總結(jié),具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-12-12

最新評論