Window.matchmedia hearing aid fires twice

I am trying to write javascript that will change some values ​​stored in a JS configuration object at certain browser breakpoints.

I saved the window.matchmedia tests inside the configuration object, and then I iterate over these object keys to add an event listener to each test, for example:

Object.keys(config.mediaQueries).map((key) =>{ config.mediaQueries[key].addListener(function(){ console.log("breakpoint change"); }); }); 

https://codepen.io/decodedcreative/pen/YQpNVO

However, when resizing the browser and performing listener callback functions, they work twice. Check out CodePen above when your console is open and you will see what I mean.

Does anyone know what I did wrong here?

+5
source share
4 answers

To answer your direct question, you have not done anything wrong. And JS does exactly what he was supposed to do.

trld There are 2 events, but only one contains the corresponding media request.

What happens when a browser hits a breakpoint, 2 events are logged. As an example, consider the case where the browser size changes from 1250 pixels to 1150 pixels. When a window hits 1199 pixels wide of your function:

 Object.keys(config.mediaQueries).map((key) =>{ config.mediaQueries[key].addListener(function(event){ console.log("breakpoint change"); }); }); 

will record 2 events. If you dive deeper and record events with:

 Object.keys(config.mediaQueries).map((key) =>{ config.mediaQueries[key].addListener(function(event){ console.log(event); }); }); 

You will see additional information about media queries. I boiled the event object to the important details below.

 // First event matches: true media: "(max-width: 1199px) and (min-width: 992px)" // Second event matches: false media: "(min-width: 1200px)" 

Here 2 events occur, but only one of the events contains the corresponding request.

So, if we want to improve your logging script, you can check the matches property:

 Object.keys(config.mediaQueries).map((key) =>{ config.mediaQueries[key].addListener(function(event){ if (event.matches) { console.log(event); } }); }); 

With this small change, only the corresponding media request will be recorded.

+4
source

If you change your console.log("breakpoint change"); to console.log(key, "breakpoint change"); , you will see that both xs and s requests are triggered when manually resizing the browser window.

If you want your callback to fire once during a time window, you will need to throttle the events or execute the behavior in some other way.

Edit: Tomasz Bubała and Brett DeWoody responds by pointing to the event.matches property as the correct and more .matchMedia specific solution to this problem.

+2
source

It seems that the event is fired before resizing and immediately after resizing. Add an if statement if you want to change the "breakpoint" immediately after changing it.

Editing: Noah Freitas may be right in case of an event for two keys when resizing. However, e.matches returns true if it matches the key, so it should work fine

  function(e) { if(e.matches) { console.log("breakpoint change"); } } 
+1
source

Not sure if this is already a complete answer. But you are right. The callback is triggered twice - for two different keys.

I changed your example, so it outputs key :

 Object.keys(config.mediaQueries).map((key) =>{ console.log("register key: '" + key + "'"); config.mediaQueries[key].addListener(function(){ console.log("breakpoint change key:'" + key + "'"); }); }); 

The resulting log output always creates two lines:

 breakpoint change key:'m' breakpoint change key:'l' 

Or for reduced width:

 breakpoint change key:'s' breakpoint change key:'m' 
0
source

Source: https://habr.com/ru/post/1269340/


All Articles