0

我知道,当与从数组动态创建的子组件一起使用时,特殊的“键”道具有助于 React 唯一地识别组件并有效地呈现更新。但我想知道何时以及为什么需要将 key 道具用于“非动态”组件。

我的应用程序使用 Reducer 和 useContext 挂钩来管理功能组件A 的状态。状态对象最多有 3 层嵌套。组件 A 更新状态并将状态对象的一部分作为道具传递给子组件B的两个实例。B 使用这些道具来渲染一个开关组件和两个输入组件。这是此层次结构的简化代码。

组分 A:

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

表格点击事件用于更新状态,组件 B 显示此选定项目的“设置”,用户可以使用组件 B 对其进行变异。

这是我面临的问题 - 当用户操作更新状态时(从表中选择一行,未在代码段中显示),我可以看到 A 和 B 在 react 开发人员工具中都收到了新数据,并且通过打印到控制台。但是,不会进行渲染以显示新数据。我想了解为什么会这样。

在查找了这个问题之后,我想我在实例化组件 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>
    </>
  );
};

再说一遍,为什么需要密钥?不反应发现道具已经改变并再次自动渲染?

4

0 回答 0