skip to Main Content

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.

2

Answers


  1. 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.

    Login or Signup to reply.
  2. 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 compared by reference, but function in component was recreated by react when component 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])
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search