Reaccionar: el componente principal actualiza el accesorio marcado, el componente de cambio lo ignora por completo

Resuelto JAMMIE asked hace 9 meses • 0 respuestas

en mis padres tengo

const [showColorbar, setShowColorbar] = useState(
  colorbarService.isColorbarToggled(viewportId),
);

Le paso este valor a

<SwitchButton
  label="Display Color bar"
  checked={showColorbar}
  onChange={() => {
    onSetColorbar({
      viewportId,
      options: {
        colormaps,
        ticks: {
          position: colorbarTickPosition,
        },
        width: colorbarWidth,
        position: colorbarContainerPosition,
        activeColormapName: colorbarInitialColormap,
      },
    });
  }}
/>;

y este es el botón de cambio

import React, { useCallback, useState } from "react";

import "./switchButton.css";

export enum SwitchLabelLocation {
  left,
  right,
}

export type SwitchButtonProps = {
  checked?: boolean;
  label?: string;
  labelLocation?: SwitchLabelLocation;
  onChange?: (checked: boolean) => void;
};

const SwitchButton = ({
  label,
  checked = false,
  onChange,
  labelLocation = SwitchLabelLocation.left,
}: SwitchButtonProps) => {
  const [isInputChecked, setIsInputChecked] = useState(checked);

  const onHandleChange = useCallback(
    (event) => {
      setIsInputChecked(event.target.checked);
      onChange?.(event.target.checked);
    },
    [onChange],
  );

  // Thanks goes to https://codepen.io/lhermann/pen/EBGZRZ for the inspiration to the code below.
  return (
    <label className="switch-button flex w-full cursor-pointer items-center justify-between text-[14px]">
      {label && labelLocation === SwitchLabelLocation.left && (
        <div>{label}</div>
      )}
      <div className="relative">
        <input
          className="absolute hidden"
          type="checkbox"
          onChange={onHandleChange}
          checked={isInputChecked}
        />
        <div className="switch-button-outer border-common-bright bg-primary-dark block h-[16px] w-[30px] rounded-full border"></div>
        <div className="switch-button-dot bg-common-bright absolute left-[4px] top-[3px] h-[10px] w-[10px] rounded-full transition duration-150 ease-in-out"></div>
      </div>
      {label && labelLocation === SwitchLabelLocation.right && (
        <div>{label}</div>
      )}
    </label>
  );
};

export default SwitchButton;

Por alguna razón, a SwitchButton no le IMPORTA cuál es el valor marcado cuando se actualiza, digamos que enciendo el interruptor y cierro el menú, la próxima vez que abra el menú, aunque el accesorio marcado que se pasa es verdadero, de alguna manera dice falso, no entiendo esto.

Intenté depurar durante horas, espero que el niño se actualice según el padre, si el valor marcado en el padre es verdadero, cuando abrí y cerré el menú, el interruptor debería estar activado, no desactivado.

JAMMIE avatar Feb 16 '24 11:02 JAMMIE
Aceptado

Parece que SwitchButton solo usa la propiedad 'checked' para inicializar 'isInputChecked' y luego opera solo en 'isInputChecked'. Después de la inicialización, 'isInputChecked' nunca se actualiza para permanecer sincronizado con 'checked'.

Solucionarlo con useEffect dentro de SwitchButton:

useEffect(()=> setIsInputChecked(marcado), [marcado]);

O convierta SwitchButton en un componente controlado operando en 'checked' en lugar de 'isInputChecked' en primer lugar (que sería mi solución preferida)

Steffen Frank avatar Feb 16 '2024 06:02 Steffen Frank