如何让React组件从Props获取本地State的初始值?
问题解决:Switch组件本地状态始终为false的修复
问题根源
你的组件同时混合了受控组件(依赖props的checked)和非受控组件(本地useState)的逻辑:父组件传入checked作为初始值,但没有在onChange回调中更新自身状态,导致组件每次渲染时checked prop始终为初始的false;同时useState的初始值仅在第一次渲染生效,后续渲染不会自动同步checked的变化,最终引发状态冲突。
解决方案一:改为非受控组件(推荐)
完全由组件内部维护状态,仅通过props传入初始值,符合你“保留本地状态、从props取初始值”的需求。
修改后的代码
import React, { useState } from 'react' import IconSvg from 'ui/Icon/IconSvg' import IconSwitchOn from 'ui/Icon/controls/switch-on' import IconSwitchOff from 'ui/Icon/controls/switch-off' interface SwitchProps { // 改为可选的初始值参数,默认false defaultChecked?: boolean // 建议将当前状态传给父组件,方便后续扩展 onChange?: (checked: boolean) => void } export const Switch: React.FC<SwitchProps> = ({ defaultChecked = false, onChange }) => { // 用defaultChecked初始化本地状态 const [check, setCheck] = useState<boolean>(defaultChecked) const onChangeLocal = () => { const newCheck = !check setCheck(newCheck) // 触发父组件回调时传递最新状态 onChange?.(newCheck) } return ( <button type="button" role="switch" onClick={onChangeLocal}> {check ? <IconSvg Svg={IconSwitchOn} /> : <IconSvg Svg={IconSwitchOff} />} </button> ) }
解决方案二:支持受控/非受控双模式
如果需要兼容父组件偶尔控制状态的场景,可以通过useEffect监听checked prop的变化,同步本地状态:
修改后的代码
import React, { useState, useEffect } from 'react' import IconSvg from 'ui/Icon/IconSvg' import IconSwitchOn from 'ui/Icon/controls/switch-on' import IconSwitchOff from 'ui/Icon/controls/switch-off' interface SwitchProps { // 改为可选,支持受控(传checked)/非受控(不传checked) checked?: boolean onChange?: (checked: boolean) => void } export const Switch: React.FC<SwitchProps> = ({ checked, onChange }) => { // 初始化状态:优先用传入的checked,否则默认false const [check, setCheck] = useState<boolean>(checked ?? false) // 监听checked prop变化,受控模式下同步本地状态 useEffect(() => { if (checked !== undefined) { setCheck(checked) } }, [checked]) const onChangeLocal = () => { const newCheck = checked !== undefined ? !checked : !check // 非受控模式下更新本地状态 if (checked === undefined) { setCheck(newCheck) } onChange?.(newCheck) } return ( <button type="button" role="switch" onClick={onChangeLocal}> {check ? <IconSvg Svg={IconSwitchOn} /> : <IconSvg Svg={IconSwitchOff} />} </button> ) }
内容的提问来源于stack exchange,提问作者Ruslan Karimov
相关产品推荐
相关产品推荐

