NOTE: this question aims to understand why this code gives this behaviour, not what alternative code would give the desired one.
I have a custom component to represent a particular form field, and I wanted to conditionally render it with different props depending on conditions. In the real example, more props change between the cases, but I have distilled it to this minimal example below, see this fiddle:
https://jsfiddle.net/xkzywjvL/1/
function DummyInput({defaultValue}) {
console.log(defaultValue)
return (
<input defaultValue={defaultValue}/>
)
}
function Picker({setContentOption})
{
const handleOptionChange = (event) => {
setContentOption(event.target.value);
};
return (
<div>
<select onChange={handleOptionChange}>
<option value="content-A">content-A</option>
<option value="content-B">content-B</option>
<option value="content-C">content-C</option>
</select>
</div>
)
}
function App() {
const [contentOption, setContentOption] = React.useState('content-A')
let inputField = null
if (contentOption === 'content-A'){
inputField = <DummyInput defaultValue="A"></DummyInput>
}
else if (contentOption === 'content-B'){
inputField = <DummyInput defaultValue="B"></DummyInput>
}
else if (contentOption === 'content-C'){
inputField = <DummyInput defaultValue="C"></DummyInput>
}
return (
<div>
<div>See that the console prints three times, meaning that
code is executed in all three versions, but only the third
re-renders the component</div>
<br/>
<Picker setContentOption={setContentOption}/>
<br/>
<div>Does not work - if / else statement in function body</div>
{inputField}
<div>Does not work - inline if else statement</div>
{(contentOption === 'content-A') && (
<DummyInput defaultValue="A"></DummyInput>
) || (contentOption === 'content-B') && (
<DummyInput defaultValue="B"></DummyInput>
) || (contentOption === 'content-C') && (<DummyInput defaultValue="C"></DummyInput>)}
<div>Works - three separate inline if statements</div>
{contentOption === 'content-A' && <DummyInput defaultValue="A"></DummyInput>}
{contentOption === 'content-B' && <DummyInput defaultValue="B"></DummyInput>}
{contentOption === 'content-C' && <DummyInput defaultValue="C"></DummyInput>}
</div>
);
}
ReactDOM.render(<App />, document.querySelector("#app"))
The app renders a form field component DummyInput with a defaultValue that changes depending on state contentOption from the parent App component (in the real example there are more differences that one prop). I expected the defaultValue to change based on the state, regardless of the conditional rendering method used.
I originally assigned the component to a variable inputField in an if - else statement, but realised that it did not update the component. Instead, if I use three separate && to render conditionally, the components do update as in the example, but not if I use an inline if-else.
By putting a console.log statement in DummyInput I can see that even though the component is not re-rendering with the updated defaultValue, the code inside the component is being executed.
What is the reason for this behaviour? The reason why I want to know is that I might be inadvertedly doing something similar elsewhere without noticing.
Similar previous questions
This question is similar to this one and this one, and if I add a "key" to the DummyInput, it works. However, I don't understand why this is needed outside of a map function, nor why three separate inline if statements work.