Для хранения выбранных значений можно использовать объект, имена свойств которого соответствуют индексам групп чекбоксов, а значения будут массивами значений, соответствующих чекбоксам выбранной группы (вперемешку, без разделения по конкретным чекбоксам). В обработчике клика чекбокса в зависимости от его checked дописываете или выбрасываете значения группы.
Для вывода значений, выбранных во всех группах берёте массив выбранных значений любой группы, и фильтруете его с условием, что элемент массива присутствует во всех массивах выбранных значений групп.
Выглядеть это может так, например:
class App extends React.Component {
state = {
selected: {},
groups: [
[
[ 'value_a1', 'value_a2', 'value_a3' ],
[ 'value_b1', 'value_b2', 'value_b3' ],
[ 'value_c1', 'value_c2', 'value_c3' ],
],
[
[ 'value_a1', 'value_b1', 'value_c1' ],
[ 'value_a2', 'value_b2', 'value_c2' ],
[ 'value_a3', 'value_b3', 'value_c3' ],
],
],
}
onChange = (e, groupIndex, itemIndex) => {
const selectedGroup = this.state.groups[groupIndex][itemIndex];
const selectedInfo = this.state.selected[groupIndex] || [];
this.setState({
selected: {
...this.state.selected,
[groupIndex]: e.target.checked
? selectedInfo.concat(selectedGroup)
: selectedInfo.filter(n => !selectedGroup.includes(n))
},
});
}
render() {
const { selected, groups } = this.state;
const matched = (selected[0] || []).filter(n => {
return groups.every((group, i) => (selected[i] || []).includes(n));
});
return (
<div>
{groups.map((group, groupIndex) => (
<ul>
{group.map((item, itemIndex) => (
<li>
<input
type="checkbox"
onChange={(e) => this.onChange(e, groupIndex, itemIndex)}
/>
{item.map(val => <span>{val}</span>)}
</li>
))}
</ul>
))}
<div>
{matched.map(val => <span>{val}</span>)}
</div>
</div>
);
}
}