如何在 React 中使用受控组件删除 :checked pseudo-class?

How to remove the :checked pseudo-class using a controlled component in React?

我有一个订阅选择组件,其中包含 3 个单独的 "plan" 组件。每个计划组件都包含一个用于选择该计划的单选按钮。因此,单选按钮没有组合在一起,而是实际上在 3 个组件中分开。

我目前能够在单击单选按钮时成功地"select" 每个计划。 "selected" 属性会针对每个计划组件进行相应更新,因此此功能可以正常工作。问题是每个单选按钮在视觉上都保持 "selected" 因为样式是通过 :checked 伪 class 应用的,当单击另一个按钮时它似乎没有得到更新。

换句话说,我点击按钮 1 -> 按钮 1 被选中,计划 1 被选中,计划 1 的边框颜色发生变化。我单击按钮 2 -> 选择按钮 2,选择计划 2,计划 2 的边框颜色发生变化,不再选择计划 1,计划 1 的边框颜色恢复正常,但计划 1 的按钮仍处于选中状态。

SubscriptionsContainer.js

const SubscriptionsContainer = (props) => {
  const [selected, setSelected] = useState('2');
  const plansList = [ 
    {
      ...plan info
    }
  ]

  const selectPlan = (e) => {
    setSelected(e.target.value);
  }

  const plansComponents = plansList.map(plan => (
    <SubscriptionPlan
      key={plan.id}
      id={plan.id}
      title={plan.title}
      price={plan.price}
      feature1={plan.feature1}
      feature2={plan.feature2}
      feature3={plan.feature3}
      feature4={plan.feature4}
      selected={plan.id === selected}
      selectPlan={selectPlan}
    />
    ));

  return (
    <FlexContainer>
      {plansComponents}
    </FlexContainer>
  )
}

SubscriptionPlan.js

const SubscriptionPlan = ({
  selected,
  id,
  title,
  price,
  feature1,
  feature2,
  feature3,
  feature4,
  selectPlan,
  ...props
}) => {

  return (
    <PlanContainer selected={selected} flexDirection="column">
      <h3>{title}</h3>
      <P>{price}/mo</P>
      <P>{feature1}</P>
      <P>{feature2}</P>
      <P>{feature3}</P>
      <P>{feature4}</P>
      <RadioInput onChange={selectPlan} selected={selected} name={id} value={id} />
    </PlanContainer>
  )
};

RadioInput.js

const RadioInput = (props) => {
  console.log(props.selected);
  return (
    <Item>
      <RadioButton
        type="radio"
        value={props.value}
        selected={props.selected}
        onChange={props.onChange}
        {...props} />
      <RadioButtonStyle/>
      <RadioButtonLabel>{props.value}</RadioButtonLabel>
    </Item>
  )
}

const Item = styled.div`
  display: flex;
  align-items: center;
  height: 48px;
  position: relative;
`;

const RadioButtonStyle = styled.label`
  position: absolute;
  top: 33%;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: white;
  border: 1px solid ${colors.primary500};
`;
const RadioButton = styled.input`
  opacity: 0;
  z-index: 1;
  border-radius: 50%;
  width: 16px;
  height: 16px;
  margin-right: 10px;
  &:hover {
    cursor: pointer;
  }
  &:hover ~ ${RadioButtonStyle} {
    background: ${colors.secondary500};
    opacity: 0.5;
    border: 1px solid ${colors.secondary600};

    &::after {
      content: "";
      display: block;
      border-radius: 50%;
      width: 8px;
      height: 8px;
      margin: 4px;
      background: white;

    }
  }
  &:focus + ${RadioButtonStyle} {
    border: 1px solid ${colors.secondary600};
  }
  &:checked + ${RadioButtonStyle} {
    background: ${colors.secondary500};
    opacity: 1;
    border: 1px solid ${colors.secondary600};
    &::after {
      content: "";
      display: block;
      border-radius: 50%;
      width: 8px;
      height: 8px;
      margin: 4px;
      box-shadow: 1px 3px 3px 1px rgba(0, 0, 0, 0.1);
      background: white;
    }
  }
`;

const RadioButtonLabel = styled.div`
  color: ${colors.primary800};
`

您可以通过为所有输入赋予相同的名称来分组,例如 name="subscriptionType",即使它们位于不同的组件中也是如此。

希望有帮助

尝试用 "checked" 替换复选框组件上的 "value" 道具。

const RadioInput = (props) => {
  console.log(props.selected);
  return (
    <Item>
      <RadioButton
        type="radio"
        // value={props.value} <-- removed
        checked={props.value} // <-- added
        selected={props.selected}
        onChange={props.onChange}
        {...props} />
      <RadioButtonStyle/>
      <RadioButtonLabel>{props.value}</RadioButtonLabel>
    </Item>
  )
}

查看可能重复的问题: