Dicts can be used to store a map of keys to values. However, in TON, it's recommended to avoid storing unbounded dicts. That is dicts that grow dynamically as time passes. The use case that you described is a dynamic one. The reason to avoid it is that your storage grows, and as it grows you have to pay more and more to keep it on the blockchain.
To store a dynamic list, you have to break it into smaller parts. This is called sharding, and you can find more info about how to do it in this great article:
Tuples are limited to 256 entries, but you can use them as an unlimited ML-style list. That means to store the first element as the first tuple element, and the rest of the list in another tuple as the second element, and again use this same structure for the rest of the list until the end which is usually a null value:
(1, (2, (3, null())))
But in FunC (and TON in general), this is only useful for working with data in memory, since when you want to store it, you have to serialize it to a Cell.