最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Defining MainButton.onClick() for Telegram Webapp correcly - Stack Overflow

programmeradmin2浏览0评论

I am trying to define window.Telegram.WebApp.MainButton.onClick() functionality to use the most recent values.

Lets see through code:

// selectedRegions is an array of strings
const [selectedRegions, setSelectedRegions] = React.useState([""]);

React.useEffect(() => {
    window.Telegram?.WebApp.MainButton.onClick(() => {
        //   window.Telegram.WebApp.sendData(selectedRegions);
        alert("main button clicked");
    });
}, [selectedRegions]);

Now as I update the selectedRegions, this useEffect is called for the number of times the state changes which also updates the MainButton.onClick() functionality. Then at the end, when the MainButton is pressed, in this case, alert() is shown the number of times the state was updated, eg, if the selectedRegions contain 3 values, the alert will be shown 3 times.

What I want is to somehow define this onClick() once or the functionality executed only once, so that I can send the selectedRegions only once with the most recent values back to the bot.

UPDATE 1: After looking into the function onEvent() in telegram-web-app.js file,

function onEvent(eventType, callback) {
    if (eventHandlers[eventType] === undefined) {
      eventHandlers[eventType] = [];
    }
    var index = eventHandlers[eventType].indexOf(callback);
    if (index === -1) {
      eventHandlers[eventType].push(callback);
    }
  };

It seems to my understanding that if the callback is present in eventHandlers["webView:mainButtonClicked"], then it will not do anything, otherwise just push it into the array. What I fail to understand is that somehow the callbacks are different, that's why they get appended to the array, justifying the multiple calls to it.

However, I am trying to use MainButton.offClick() to remove the from eventHandlers array, have not succeeded yet. If anyone has done so, it would be highly appreciated.

I am trying to define window.Telegram.WebApp.MainButton.onClick() functionality to use the most recent values.

Lets see through code:

// selectedRegions is an array of strings
const [selectedRegions, setSelectedRegions] = React.useState([""]);

React.useEffect(() => {
    window.Telegram?.WebApp.MainButton.onClick(() => {
        //   window.Telegram.WebApp.sendData(selectedRegions);
        alert("main button clicked");
    });
}, [selectedRegions]);

Now as I update the selectedRegions, this useEffect is called for the number of times the state changes which also updates the MainButton.onClick() functionality. Then at the end, when the MainButton is pressed, in this case, alert() is shown the number of times the state was updated, eg, if the selectedRegions contain 3 values, the alert will be shown 3 times.

What I want is to somehow define this onClick() once or the functionality executed only once, so that I can send the selectedRegions only once with the most recent values back to the bot.

UPDATE 1: After looking into the function onEvent() in telegram-web-app.js file,

function onEvent(eventType, callback) {
    if (eventHandlers[eventType] === undefined) {
      eventHandlers[eventType] = [];
    }
    var index = eventHandlers[eventType].indexOf(callback);
    if (index === -1) {
      eventHandlers[eventType].push(callback);
    }
  };

It seems to my understanding that if the callback is present in eventHandlers["webView:mainButtonClicked"], then it will not do anything, otherwise just push it into the array. What I fail to understand is that somehow the callbacks are different, that's why they get appended to the array, justifying the multiple calls to it.

However, I am trying to use MainButton.offClick() to remove the from eventHandlers array, have not succeeded yet. If anyone has done so, it would be highly appreciated.

Share Improve this question edited Sep 8, 2022 at 6:29 VecopWall 6771 gold badge8 silver badges24 bronze badges asked Jul 4, 2022 at 9:11 Rizwan KhalidRizwan Khalid 411 silver badge5 bronze badges 0
Add a ment  | 

4 Answers 4

Reset to default 3

I have faced exactly same issue. I had some buttons that updates state and on main button click I wanted to send that state, but as you mentioned telegram stores all callbacks in array and when you call sendData function, web app gets closed and only first callback is executed. If you tried to remove function with offClick, I think that didn't worked, because callbacks are pared by reference, but function in ponent was recreated by react when ponent is re-rendered, so, that's why offClick failed to remove that function. In this case solution would be like this

  const sendDataToTelegram = () => {
    window.Telegram.WebApp.sendData(selectedRegions);
  }

  useEffect(() => {
    window.Telegram.WebApp.onEvent('mainButtonClicked', sendDataToTelegram)
    return () => {
      window.Telegram.WebApp.offEvent('mainButtonClicked', sendDataToTelegram)
    }
  }, [sendDataToTelegram])

If you are not familiar with this syntax - return in useEffect is callback that is called before new useEffect is called again

Or you can solve this also with useCallback hook to recreate function only when selected region state is changed. Like this:

  const sendDataToTelegram = useCallback(() => {
    window.Telegram.WebApp.sendData(selectedRegions);
  }, [selectedRegions])

  useEffect(() => {
    window.Telegram.WebApp.onEvent('mainButtonClicked', sendDataToTelegram)
    return () => {
      window.Telegram.WebApp.offEvent('mainButtonClicked', sendDataToTelegram)
    }
  }, [sendDataToTelegram])

I use Angular with typescript and I ran into this problem too. But I finally found a solution: for some reason if I pass a callback like this - "offClick(() => this.myFunc())" the inner "indexOf" of the "offEvent" cannot find this callback and returns "-1". So I ended up with:

setOnClick() {
  let f = () => this.myFunc;
  window.Telegram.WebApp.MainButton.onClick(f);
}

setOffClick() {
  let f = () => this.myFunc;
  window.Telegram.WebApp.MainButton.offClick(f);
}

myFunc() {
  console.log('helloworld');
}

Hope this helps.

  useEffect(() => {
    if (isShow) {
      Telegram.WebApp.MainButton.setText('');
      Telegram.WebApp.MainButton.show();
      Telegram.WebApp.MainButton.enable();
      Telegram.WebApp.MainButton.onClick(setSelectedRegionsHandler);
    }
    return () => {
      Telegram.WebApp.MainButton.hide();
      Telegram.WebApp.MainButton.offClick(setSelectedRegionsHandler);
    };
  }, [isShow, setSelectedRegionsHandler]);

The easiest way - to copy telegram-web-app.js to your repository and rewrite function onEvent for WebView.

I rewrote it to this:

  function onEvent(eventType, callback) {
    eventHandlers[eventType] = [callback];
  };
发布评论

评论列表(0)

  1. 暂无评论