Post

Chat) Array.prototype.reduce()

This post was migrated from Tistory. You can find the original here.

While building a chat application, I wanted a user’s profile picture to show only on the first message of a consecutive run of chats from that same user.

For a run of consecutive messages, there should be one profile picture shared across multiple chat bubbles.

So I needed to transform something like:

[ responseMsg, responseMsg, responseMsg ... ]

into a grouped form like:

[[ responseMsg, responseMsg ], [responseMsg, responseMsg, responseMsg ...]]

The idea is that if the sender of the previous message matches the sender of the next one, they should end up in the same sub-array.

Since this requires remembering the state at the previous index, reduce (as an accumulator) came to mind.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
    useEffect(() => {
        if (msgArr.length != 0) {
            const resArr: responseMsgDto[][] = [];
            let cacheArr: responseMsgDto[] = [];
            if (msgArr.length == 1) resArr.push(msgArr); // fix
            msgArr.reduce((acc, cur, idx) => {
                if (cacheArr.length == 0) cacheArr = [acc];
                if (acc.userId != cur.userId) {
                    resArr.push(cacheArr);
                    cacheArr = [];
                }
                cacheArr.push(cur);
                if (idx == msgArr.length - 1) {
                    resArr.push(cacheArr);
                }
                return cur;
            });
            // console.log(resArr);
            setReMsgArr(resArr);
        }
    }, [msgArr])

I considered producing the result directly from reduce’s return value, but that looked overly complicated, so I just pulled resArr out as an external array instead.

In the middle of the iteration: if the user is the same, keep pushing onto cacheArr; if the user differs, push cacheArr into resArr and reset cacheArr to empty.

At the very start, cacheArr doesn’t yet contain the first element, so it’s initialized as [ acc ].

At the very end, whatever is left accumulated in cacheArr gets pushed into resArr.

Fix)

If the array’s length is 1, reduce never runs the callback at all — it just returns the accumulator value directly and finishes.

This post is licensed under CC BY-NC 4.0 by the author.