The Evolution of a React Prototype

Madeline Streilein background

Madeline Streilein —

OG Image

The goal: create the matrix.

 

There are up to 3 questions

There are answers for these questions

There is a table with results

The number of results is variable

The content of the results (table headings, table rows) is variable

If answers are selected for the questions, results in the table are hidden if they do not meet the selected criteria

 

 

Iteration 1

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>
    ...
  );
}