Извлечение случайного элемента массива выносим в отдельную функцию:
const random = arr => arr[Math.random() * arr.length | 0];
Дальше можно получить случайный элемент случайного элемента:
const item = random(random(Object.values(state.themes)));
Или вложенный массив превратить в плоский и получить случайный элемент один раз:
const item = random(Object.values(state.themes).flat());
Какой из вариантов предпочесть? Зависит от того, как должны распределяться вероятности выпадения элементов - в случае, если выбирать элемент в два приёма, и размеры вложенных массивов различны, вероятности будут разными для разных массивов. Предположим, есть два вложенных массива, в одном два элемента, во втором сто. Получается, у элементов первого массива шанс быть выбранными один к четырём (один из двух массивов, один из двух элементов - 0.5 умножается на 0.5), а у элементов второго - один к двумстам (0.5 * 0.01).
То есть, если должны быть равны вероятности выпадения элементов - объединяем вложенные массивы в один. Если равными должны быть вероятности принадлежности выбранного элемента к вложенным массивам, то выбираем сначала массив, а потом элемент внутри него.
Но что если вероятности выпадения элементов должны быть равны, а размеры вложенных массивов велики, и не хотелось бы тратить на их объединение ни время, ни память? Возвращаемся к двум выборам, но выбирать вложенные массивы надо не с равными вероятностями, а учитывая их размеры:
function weightedRandom(arr, key) {
const rand = Math.random() * arr.reduce((acc, n) => acc + n[key], 0);
let sum = 0;
return arr.find(n => (sum += n[key]) > rand);
}
const item = random(weightedRandom(Object.values(state.themes), 'length'));