Как свойство key работает в нединамическом дочернем компоненте и почему оно важно для рендеринга обновлений?

Я понимаю, что специальная опция key при использовании с дочерними компонентами, которые создаются динамически из массивов, помогает React однозначно идентифицировать компоненты и эффективно отображать обновления. Но я хотел бы знать, когда и почему необходимо использовать ключевую опору для «нединамического» компонента.

В моем приложении для управления состоянием функционального компонента A используются обработчики Reducer и useContext . Объект состояния имеет максимум 3 уровня вложенности. Компонент A обновляет состояние и передает часть государственного объекта в качестве реквизита до двух экземпляров ребенка компонента B . B использует эти реквизиты для рендеринга компонента переключателя и двух компонентов ввода. Вот упрощенный код этой иерархии.

Компонент А:

      const A: FC = () => {
// ....
// graphql queries to get data and update state using reducer
// ...
return (
    <B
      enabled={data.a.b.enabled}
      value1={data.a.b.value1}
      value2={data.a.b.value2}
    />
    <B
      enabled={data.a.b.enabled}
      value1={data.a.b.value1}
      value2={data.a.b.value2}
    />
  );
};

Компонент B:

        const B: FC = props => {
  const { value1, value2, enabled} = props;  // there are other props as well
  
  return (
    <>
      <div className={someClassLogic}>
        <Switch
          onChange={onValueChange}
          isChecked={enabled}
          disabled={disabled}
        />
      </div>
        <div className={someClassLogic} >
          <Input
            input={value1}
            disabled={disabled}
          />
        </div>
      <div className={someClassLogic}>
        <Input
          input={value2}
          disabled={disabled}
         />
      </div>
    </>
  );
};

Событие щелчка tablerow используется для обновления состояния, и компонент B отображает «настройки» этого выбранного элемента, которые пользователь может изменить с помощью компонента B.

Вот проблема, с которой я столкнулся: когда состояние обновляется действием пользователя (выбор строки из таблицы, не показанной во фрагменте), я вижу, что как A, так и B получают новые данные в средствах разработки реагирования и путем печати на консоли. Но рендеринг для отображения новых данных не выполняется. Я хотел бы понять, почему это так.

Изучив эту проблему, я решил, что мне нужна ключевая опора при создании экземпляра компонента B (в ответах четко не объясняется, почему). При следующем добавлении значения отображались правильно. Почему здесь необходим ключ и почему он работает только тогда, когда ключ содержит все реквизиты, которые могут изменять значения? Если я использую только uniqueId в качестве ключа, value1 и value2 снова не будут отображаться правильно. Если у меня много изменяемых реквизитов, нужно ли мне добавить к ним еще и ключ? Нет ли менее корявого подхода?

Обновленный компонент A:

      const A: FC = () => {

return (
    <B
      key={`${data.a.uniqueId}-
      ${data.a.b.value1}-
      ${data.a.b.value2}
      enabled={data.a.b.enabled}
      value1={data.a.b.value1}
      value2={data.a.b.value2}
    />
    <B
      key={`${data.a.uniqueId}-
      ${data.a.b.value1}-
      ${data.a.b.value2}
      enabled={data.a.b.enabled}
      value1={data.a.b.value1}
      value2={data.a.b.value2}
    />
  );
};

Кроме того, я заметил, что хотя щелчок по строке таблицы теперь отображает правильное значение в компоненте B, но щелчок по строке, которая пока не изменена пользователем, приведет к тому, что ранее отрисованные значения останутся в компонентах Input1 и Input2 (вместо этого бланка). Поэтому мне пришлось добавить ключи к входам с прикрепленным к нему состоянием, что устранило эту проблему.

Обновленный компонент B:

        const B: FC = props => {
  const { value1, value2, enabled} = props;  // there are other props as well
  
  return (
    <>
      <div className={someClassLogic}>
        <Switch
          onChange={onValueChange}
          isChecked={enabled}
          disabled={disabled}
        />
      </div>
        <div className={someClassLogic} >
          <Input
            key={`value1-${enabled}`}
            input={value1}
            disabled={disabled}
          />
        </div>
      <div className={someClassLogic}>
        <Input
          key={`value2-${enabled}`}
          input={value2}
          disabled={disabled}
         />
      </div>
    </>
  );
};

Опять же, зачем нужен ключ? Не реагирует, выясняет, что реквизит изменился, и снова автоматически рендерится?

0 ответов

Другие вопросы по тегам