React中useEffect同步defaultValue是否为反模式?如何简化代码?
问题:简化Toggle标签页组件代码,避免React反模式
我写了一个接收defaultValue的Toggle标签页组件,目前用useState把value初始化为defaultValue,又用useEffect监听defaultValue的变化来更新value,但我觉得这属于React反模式,请问怎么简化这段组件代码?
我的组件实现代码:
const Toggle = ({ defaultValue, leftItem, rightItem, onValueChange, ...props }) => { const [value, setValue] = useState(defaultValue); useEffect(() => { setValue(defaultValue); }, [defaultValue]); return ( <div {...props}> <ToggleGroup type="single" value={value} onValueChange={(value) => { if (value) { setValue(value); } }} > <ToggleGroupItem value={leftItem.value}> {leftItem.label} </ToggleGroupItem> <ToggleGroupItem value={rightItem.value}> {rightItem.label} </ToggleGroupItem> </ToggleGroup> </div> ); };
解决方案
你现在的写法确实属于React里的反模式——用useEffect同步props到state完全没必要,我们可以通过区分受控/非受控组件的逻辑来优化:
核心优化点
- 你的组件现在是非受控模式(用
defaultValue初始化状态),这种模式下不需要监听defaultValue的变化,因为defaultValue只负责提供初始值,后续状态由组件内部维护; - 状态变化时要记得调用
onValueChange,把新值同步给父组件,避免状态割裂; - 把零散的回调逻辑抽成独立函数,代码更清晰。
优化后的代码
const Toggle = ({ defaultValue, leftItem, rightItem, onValueChange, ...props }) => { // 直接用defaultValue初始化内部state,无需额外监听 const [value, setValue] = useState(defaultValue); const handleValueChange = (newValue) => { if (newValue) { setValue(newValue); // 调用父组件传入的回调,同步状态变化 onValueChange?.(newValue); } }; return ( <div {...props}> <ToggleGroup type="single" value={value} onValueChange={handleValueChange} > <ToggleGroupItem value={leftItem.value}> {leftItem.label} </ToggleGroupItem> <ToggleGroupItem value={rightItem.value}> {rightItem.label} </ToggleGroupItem> </ToggleGroup> </div> ); };
进阶:支持受控模式
如果后续需要让组件同时支持受控模式(由父组件传入value并控制状态),可以调整成如下写法,兼容两种模式:
const Toggle = ({ defaultValue, value: controlledValue, // 受控模式的外部value leftItem, rightItem, onValueChange, ...props }) => { // 区分受控/非受控:外部传了value就用外部的,否则用内部state const [internalValue, setInternalValue] = useState(defaultValue); const currentValue = controlledValue !== undefined ? controlledValue : internalValue; const handleValueChange = (newValue) => { if (newValue) { // 受控模式下不更新内部state,直接触发回调让父组件处理 if (controlledValue === undefined) { setInternalValue(newValue); } onValueChange?.(newValue); } }; return ( <div {...props}> <ToggleGroup type="single" value={currentValue} onValueChange={handleValueChange} > <ToggleGroupItem value={leftItem.value}> {leftItem.label} </ToggleGroupItem> <ToggleGroupItem value={rightItem.value}> {rightItem.label} </ToggleGroupItem> </ToggleGroup> </div> ); };
内容的提问来源于stack exchange,提问作者Jenny Le
相关产品推荐
相关产品推荐

