React组件挂载/卸载与render中if-else的关系及子组件构造与重渲染问题
Great question—this is a super common point of confusion when working with React's reconciliation process. Let's break this down clearly, step by step.
React’s reconciliation algorithm (the process that updates the real DOM from your virtual DOM) uses two key checks to decide whether to update an existing component or replace it entirely:
- The type of the element (e.g.,
<div>vs<ComponentA>) - The
keyprop (if provided)
When your render function uses if-else to return different elements/components:
- If the elements are of different types (e.g.,
<ComponentA>vs<ComponentB>), React will immediately unmount the current component (triggering its unmount lifecycle hooks likecomponentWillUnmountoruseEffectcleanup functions) and mount the new one (triggeringconstructor,componentDidMount, oruseEffectsetup callbacks). - If the elements are of the same type, React will try to update the existing component instance with new props/state instead of unmounting it—unless you use distinct
keyprops to tell React they’re separate instances.
Let’s clarify the difference between when a child component is constructed vs when it rerenders:
- Constructor (or initial mount logic):
- For class components: The
constructorruns exactly once, when the component is first mounted. It won’t run again during rerenders. - For function components: The entire function runs on every rerender, but initializers like
useState(initialValue)only use the initial value on the first mount. Hooks likeuseEffect(() => {}, [])(with an empty dependency array) also only run once on mount.
- For class components: The
- Rerender timing:
- A child rerenders when:
- Its parent component rerenders (unless the child is memoized with
React.memo) - Its own props change
- Its own state changes
- Its parent component rerenders (unless the child is memoized with
- During a rerender, React updates the component’s UI with new props/state but does not trigger mount/unmount lifecycle steps. For class components, this means
renderruns again butconstructorandcomponentDidMountdon’t. For function components, the function body executes again but mount-only hooks don’t re-run.
- A child rerenders when:
key Prop The key prop is React’s way of identifying unique component instances, even if they’re the same type. It’s most commonly used in lists, but it’s critical for if-else switches too:
- Without a
key, React treats same-type components as the same instance. So if you switch between<ComponentA id="1">and<ComponentA id="2">, React will just update the existingComponentA’sidprop instead of creating a new instance. - With distinct
keys, React recognizes them as separate instances. So switching between<ComponentA key="1" id="1">and<ComponentA key="2" id="2">will trigger an unmount of the first instance and a mount of the second.
Here’s a quick code example to illustrate:
// Without key: Updates existing ComponentA instance function Parent() { const [useFirst, setUseFirst] = useState(true); return useFirst ? <ComponentA id="1" /> : <ComponentA id="2" />; } // With key: Unmounts old ComponentA, mounts new one function Parent() { const [useFirst, setUseFirst] = useState(true); return useFirst ? <ComponentA key="1" id="1" /> : <ComponentA key="2" id="2" />; }
Let’s tie this all together with the specific scenario you asked about:
- If A and B are different component types (e.g.,
<UserProfile>vs<ProductList>):- Every time the if-else switches, React will unmount the current component (running its cleanup logic) and mount the new one (running its mount logic). No
keyis needed here—React’s type check is enough to trigger a full replacement.
- Every time the if-else switches, React will unmount the current component (running its cleanup logic) and mount the new one (running its mount logic). No
- If A and B are the same component type but with different props:
- Without a
key, React will update the existing component’s props and rerender it (no unmount/mount). - With unique
keys, React will unmount the old instance and mount a new one, resetting any internal state or mount-only logic for the component.
- Without a
For example, with function components:
function Parent() { const [showA, setShowA] = useState(true); return ( <div> <button onClick={() => setShowA(!showA)}>Toggle Component</button> {showA ? <ChildComponent label="A" /> : <ChildComponent label="B" />} </div> ); } function ChildComponent({ label }) { useEffect(() => { console.log(`Child ${label} mounted`); return () => console.log(`Child ${label} unmounted`); }, []); return <div>Child {label}</div>; }
- Without a
key, clicking the button will only update thelabelprop—you’ll never see the unmount/mount logs. - Add
key={label}to<ChildComponent>: Now clicking the button will log "Child A unmounted" followed by "Child B mounted" (and vice versa), since React treats them as separate instances.
内容的提问来源于stack exchange,提问作者Mong H. Ng

