I think ArraysOfArrays solves the opposite problem, i.e. it’s like eachslice not like cat. There is a small zoo of packages for doing cat-like things, my summary of all the ones I found is here. RecursiveArrayTools has the slightly weird feature that linear indexing doesn’t do what you’d expect for a 3-array: B[1] isa Matrix.
You can use that here, with a reshape:
julia> A = [rand(4, 4) for _ in 1:10000];
julia> @time B = reduce(hcat, A); summary(B) # done efficiently
0.000543 seconds (2 allocations: 1.221 MiB)
"4×40000 Matrix{Float64}"
julia> C = reshape(B, 4, 4, :); summary(C) # almost free
"4×4×10000 Array{Float64, 3}"
julia> C[1,2,3] == A[3][1,2]
true
julia> @time C == reduce((x,y) -> cat(x, y, dims=3), A) # done pairwise, slow!
0.193491 seconds (262.96 k allocations: 396.856 MiB, 9.68% gc time, 28.20% compilation time)
true
Although this reshape doesn’t work beyond matrices, and it would be convenient to have a specific function. In julia#21672 it sounds like someone just has to get around to writing it.