Victor Gorban
Victor Gorban

Reputation: 1671

Huge freezes when rendering long selects in React

I have a table, 50-200 rows. It renders OK with text values, but when I add selects, it starts to freeze on render. The selects have nearly 1500 options each.

That is the table body:

<tbody className="tbody">
          {tableSubjects.map((item, idx) => (
            <tr key={item.id} className="tr">
              <td className="td">{idx + 1}</td>
              <td
                className={`td object ${errors[`educational_documents.10.data.table_subjects[${idx}].subject_id`] ? "error" : ""
                  }`}
              >
                <select
                  tabIndex="-1"
                  className="input table-select w-100"
                  id={`educational_documents.10.data.table_subjects[${idx}].subject_id`}
                  onChange={(e) => handleChange_subject_id(e, item)}
                  required
                  readOnly={!edit}
                  defaultValue={_.get(tableSubjects, `[${idx}].subject_id`, '')}
                >
                  <option value="" disabled>
                    Select one
                  </option>
                  {subjects.filter(subject => subject.type == 'All' || subject.type == 'OO').map((subject) => (
                    <option key={subject.id} value={subject.id}>
                      {subject.code} {subject.name}
                    </option>
                  ))}
                </select>
                <span className="error-message w-100">
                  {errors[`educational_documents.10.data.table_subjects[${idx}].subject_id`]}
                </span>
              </td>
              <td className="td mark">
                <input
                  type="number"
                  readOnly={!edit}
                  id={`educational_documents.10.data.table_subjects[${idx}].subject_mark`}
                  min="0"
                  step="1"
                  max={scoreSystem}
                  class="input table-input w-100"
                  required
                  onChange={(e) => handleChange_subject_mark(e, item)}
                  defaultValue={_.get(tableSubjects, `[${idx}].subject_mark`, '')}
                  onKeyDown={window.preventTab}
                />
              </td>
              <td className="td actions ">
                <button type="button"
                  tabIndex="-1"
                  readOnly={!edit}
                  className="btn trash"
                  onMouseDown={(e) => removeTableSubject(e, item)}
                >
                  <i className="uil uil-trash-alt"></i>
                </button>
              </td>
            </tr>
          ))}
        </tbody>

subjects.length is nearly 1500. When I don't render selects, freezes are gone. But I do need to let our users to select the value. How can I achieve that?

Maybe transform some div into select on mouseOver?

Upvotes: 0

Views: 1519

Answers (1)

Oleksandr Kovalenko
Oleksandr Kovalenko

Reputation: 616

One way to optimize this is to create a component for select input. This has to be a functional component which would allow React to optimize away some unnecessary re-renderings of the select field.

Also, the result of this filter has to be memoized:

subjects.filter(subject => subject.type == 'All' || subject.type == 'OO')

More on memoization here

const memoizedSubjects = useMemo(
  () => subjects.filter(subject => subject.type == 'All' || subject.type == 'OO'),
  []
);

Upvotes: 1

Related Questions