如何不使用useEffect且不卸载组件,从props更新React组件状态?
useEffect or Component Unmounting Great question! I totally get why you're frustrated with using useEffect for this—it does feel like a misuse of the hook (since this isn't a "side effect" in the traditional sense), and the double re-renders are a real pain. Luckily, there's a clean, semantically correct way to sync your internal component state with props without relying on useEffect or unmounting the component.
The Core Idea
Instead of using useEffect to react to prop changes after rendering, we can handle the state sync directly during the render phase. We'll use a ref to track the previous value of the prop, so we only update the internal state when the prop actually changes (avoiding infinite re-renders).
Modified Implementation
Here's how to adjust your CompoundInput component to remove the useEffect:
import "./styles.css"; import { useState, useRef } from "react"; export default function App() { const [state, setState] = useState(0); const handleChange = (change) => { console.log("change", change); setState(change); }; return ( <div className="App"> <CompoundInput value={state} onChange={handleChange} /> </div> ); } function CompoundInput(props) { const [internalState, setInternalState] = useState(props.value); const prevPropValueRef = useRef(props.value); // Sync internal state with props during render phase (no useEffect needed) if (props.value !== prevPropValueRef.current) { setInternalState(props.value); prevPropValueRef.current = props.value; } return ( <> <input type="number" value={internalState} onChange={(e) => setInternalState(e.target.value)} onBlur={(e) => props.onChange(e.target.value)} /> <input type="number" value={internalState} onChange={(e) => setInternalState(e.target.value)} onBlur={(e) => props.onChange(e.target.value)} /> </> ); }
Why This Works
- Semantically Correct: This logic is part of the component's core rendering and state management, not a side effect. We're ensuring the internal state stays in sync with the prop before the component renders, which aligns with how React expects state to be managed.
- No Extra Re-renders: Unlike
useEffect(which triggers an extra render after the initial one), this handles the state update during the initial render cycle. When the prop changes, the component will render once with the updated state, not twice. - Component Persists: Unlike the
keyhack, this doesn't unmount and remount the component—all internal state (and component instance) remains intact, except when explicitly synced with the prop.
How It Fits Your Use Case
This approach perfectly supports your compound input scenario:
- The two input boxes still sync in real-time via
internalStatewithout notifying the parent. - The parent can update the
valueprop at any time, and the internal state will sync immediately. - The
onChangecallback only fires when the input loses focus, as intended.
内容的提问来源于stack exchange,提问作者Ziggy

