React问题:父组件更新checked属性,SwitchButton组件未同步状态
问题根源
SwitchButton组件内部维护了独立的isInputChecked本地状态,父组件传入的checked仅作为该状态的初始值使用。当父组件的showColorbar状态更新时,子组件的checked props会变化,但本地状态不会自动同步,导致显示状态与父组件不一致。
解决方案
方案一:改为完全受控组件(推荐)
移除子组件的本地状态,完全依赖父组件传入的checked控制组件状态,这是React受控组件的标准写法,能彻底避免状态不同步问题。
修改后的SwitchButton代码:
import React, { useCallback } 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 onHandleChange = useCallback( (event) => { onChange?.(event.target.checked); }, [onChange], ); 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={checked} /> <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 top-[3px] h-[10px] w-[10px] rounded-full transition duration-150 ease-in-out ${checked ? 'left-[16px]' : 'left-[4px]'}`}></div> </div> {label && labelLocation === SwitchLabelLocation.right && ( <div>{label}</div> )} </label> ); }; export default SwitchButton;
方案二:保留本地状态,同步props变化
如果需要保留子组件的本地状态(比如有临时交互需求),可以通过useEffect监听checked props的变化,主动同步到本地状态:
修改后的SwitchButton代码:
import React, { useCallback, useState, useEffect } 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); // 监听props的checked变化,同步到本地状态 useEffect(() => { setIsInputChecked(checked); }, [checked]); const onHandleChange = useCallback( (event) => { setIsInputChecked(event.target.checked); onChange?.(event.target.checked); }, [onChange], ); 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 ${isInputChecked ? 'left-[16px]' : '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;
额外检查点
确保父组件的showColorbar状态能正确反映colorbarService的最新状态,可在父组件中添加监听:
useEffect(() => { setShowColorbar(colorbarService.isColorbarToggled(viewportId)); }, [viewportId, colorbarService]);
内容的提问来源于stack exchange,提问作者JAMMIE
相关产品推荐
相关产品推荐

