With Immutable.js collections, the idea is to detect any changes before any transformations and side-effects are run. You could, for example, detect changes after transformations but before side-effects:
const myList = List.of(1, 2, 3);
const mySideEffect = (list) => {
const transformed = list
.map(v => v * v);
if (!transformed.equals(mySideEffect.prev)) {
mySideEffect.prev = transformed;
transformed.forEach(
v => console.log('transformed', v)
);
}
};
mySideEffect(myList);
// -> transformed 1
// -> transformed 4
// -> transformed 9
mySideEffect(myList.set(0, 1));
mySideEffect(myList.push(4));
// -> transformed 1
// -> transformed 4
// -> transformed 9
// -> transformed 16
mySideEffect(myList.push(4));
The mySideEffect() function transforms a list of numbers and then iterates over the results, logging the values. The second and fourth calls to mySideEffect() don't log any values, because we're passing in the same value that was used in the previous call. These values are stored in the prev property of the function, and if the list argument is the same collection, we skip the side-effect.
The problem with this approach is that we're comparing the result of the transformation with a previous transformation result. You don't need to do this. Instead, you should only compare the collection argument itself:
const myList = List.of(1, 2, 3);
const myModifiedList = myList.push(4);
const mySideEffect = (list) => {
if (list !== mySideEffect.prev) {
mySideEffect.prev = list;
list
.map(v => v * v)
.forEach(v => console.log('transformed', v));
}
};
mySideEffect(myList);
// -> transformed 1
// -> transformed 4
// -> transformed 9
mySideEffect(myList.set(0, 1));
mySideEffect(myModifiedList);
// -> transformed 1
// -> transformed 4
// -> transformed 9
// -> transformed 16
mySideEffect(myModifiedList.set(0, 1));
We've introduced two improvements to mySideEffect() here. First, we're detecting changes to the collection before any transformations are run. This could potentially save a lot of computing effort. Second, since we're detecting changes before transformations happen, we only care about mutative methods, which means that we can compare using strict inequality instead of equals(). This is another potential performance improvement.
One downside to mySideEffect() is that it's not a generic solution. Your application will likely have several side-effects. Another downside is that your side-effect functions could need more than a single collection argument in order to transform data needed by the side-effect.