Disclaimer: this first approach was largely more an exploration the useRef
hook and does not represent the best usage of ReactJS. Part of the reason that React is so powerful and fast is that it is declarative. Using useRef may feel familiar to devs who are used to jQuery or vanilla JS, but there are very few scenarios when one should use the useRef hook.
To control the visibility of the table results,
function App() {
// Create a ref to store native DOM <tr> elements
const optionRefs = useRef([]);
optionRefs.current = [];
// Dynamically create refs for each <tr> elements
const addToOptionRefs = el => {
if (el && !optionRefs.current.includes(el)) {
optionRefs.current.push(el);
}
}
// If <tr> option does not include checked answer, hide element
const filterResults = e => {
// capture event
let clickedAnswer = e.target;
// if checked
if (clickedAnswer.checked) {
// get id
let checkedAnswer = clickedAnswer.id;
/* Check to see if answer is already represented in state.
* If it isn't, add to state.
*/
selectedAnswers.includes(checkedAnswer)
? null
: setSelectedAnswers(selectedAnswers => [...selectedAnswers, checkedAnswer])
// set aria attribute on input
clickedAnswer.setAttribute('aria-checked', true);
// if unchecking an answer
} else if (!clickedAnswer.checked) {
// remove answer from copy of answers
let updatedAnswers = selectedAnswers.filter(function(answer) {
return answer !== clickedAnswer.id;
});
// update state
setSelectedAnswers(updatedAnswers);
// reset aria attribute on input
clickedAnswer.setAttribute('aria-checked', false);
}
};
return (
...
<tbody>
{matrix &&
matrix.results.map((columns, index) => {
// Display options as rows, with answers encoded in classNames
return (
<React.Fragment key={index}>
<tr
id={`option-${index}`}
key={index}
ref={addToOptionRefs}
aria-hidden="false"
className={_.map(
columns.answers,
(answer, questionIndex) => {
// Create className for each answer code
return answer.length === 1
? `q-${questionIndex}-${answer}`
: answer.map(indicies => {
return `q-${questionIndex}-${indicies}`;
}).join(' ')
}
).join(' ')}
>
{_.map(columns.columns, (column, columnIndex) => {
// Render column content
return <td key={columnIndex}>{column}</td>;
})}
</tr>
</React.Fragment>
);
})}
</tbody>
...
);
}