DEV Community

Cover image for Window resize observer based on RxJS combineLatest operator
dqunbp
dqunbp

Posted on • Updated on

Window resize observer based on RxJS combineLatest operator

To better understand how rxjs/combineLatest works, I'm going to create a simple window resize observer function.

Some requirements:

The function should accept a callback that will be called whenever the window is resized.

function createWindowResizeObserver(callback) {
  ...
}
Enter fullscreen mode Exit fullscreen mode

The callback function will takes an object with dimensions:

function resizeCallback(dimensions) {
  const { width, height } = dimensions;
  console.log({ width, height });
}
Enter fullscreen mode Exit fullscreen mode

Finally, createWindowResizeObserver must return an unsubscribe function to unsubscribe from these events later, if necessary.

const unsubscribe = createWindowResizeObserver(resizeCallback);

// unsubscribe later if necessary 
unsubscribe();
Enter fullscreen mode Exit fullscreen mode

Let's implement this!

First, create a stream of window width and height changes

import { fromEvent } from "rxjs";
import { map } from "rxjs/operators";

// Create a stream from `window` resize events
// and map it to get width of window
const width = fromEvent(window, "resize").pipe(
  map(() => window.innerWidth)
);

// Do the same with height
const height = fromEvent(window, "resize").pipe(
  map(() => window.innerHeight)
);
Enter fullscreen mode Exit fullscreen mode

Then create a dimensions stream.
To do that I need to combine each change of width with latest value of height and vice versa :)
And then map result to the required shape

// add combineLatest to imports
import { fromEvent, combineLatest } from "rxjs";

// combine here
const combined = combineLatest(width, height);
// `combined` produces an array of width and height values
const dimensions = combined.pipe(
  map(([width, height]) => ({ width, height }))
);
Enter fullscreen mode Exit fullscreen mode

It will be good to add little throttling to prevent high cpu utilization

import { map, throttleTime } from "rxjs/operators";

const dimensions = combined.pipe(
  throttleTime(100),
  map(([width, height]) => ({ width, height }))
);
Enter fullscreen mode Exit fullscreen mode

To subscribe on dimensions stream use subscribe method

// subscribe method returns the unsubscribe function
const unsubscribe = dimensions.subscribe(callback);
Enter fullscreen mode Exit fullscreen mode

Finally wrap up all stuff to single function:

import { fromEvent, combineLatest } from "rxjs";
import { map, throttleTime } from "rxjs/operators";

function createWindowResizeObserver(callback) {
  const width = fromEvent(window, "resize").pipe(
    map(() => window.innerWidth)
  );

  const height = fromEvent(window, "resize").pipe(
    map(() => window.innerHeight)
  );

  const combined = combineLatest(width, height);

  const dimensions = combined.pipe(
    throttleTime(100),
    map(([width, height]) => ({ width, height }))
  );

  const unsubscribe = dimensions.subscribe(callback);

  return unsubscribe;
}
Enter fullscreen mode Exit fullscreen mode

And that's all!
Let's check the result

Open the Console and change preview window with or height

Top comments (0)