React: How to show a different component on click
By Flavio Copes
Learn how to show a different React component when a button is clicked by storing a value in useState and conditionally rendering based on that state.
To show a different component when a button is clicked, store a value in state with useState, change it in the click handler, and render one component or the other based on that value.
This comes up all the time. Think about a navigation structure: you click “Add a trip” and the button disappears, replaced by a form.
In this example I’m managing the state centralized in the App component.
The button component
First, the button. It receives the click handler via props, so it doesn’t need to know anything about the state:
const AddTripButton = (props) => {
return <button onClick={props.addTrip}>Add a trip</button>
}
export default AddTripButton
Storing what to show in state
In the App component, import useState from React:
import { useState } from 'react'
then declare a state variable. I use a string that describes what the screen is showing:
const [state, setState] = useState('start')
'start' is the initial value, so the button shows up first.
Conditional rendering
In the JSX you show and hide different components based on this state value:
function App() {
const [state, setState] = useState('start')
return (
<div>
{state === 'start' && (
<AddTripButton addTrip={() => setState('add-trip')} />
)}
{state === 'add-trip' && <AnotherComponent />}
</div>
)
}
The && trick works because React renders the right side of the expression only when the left side is true. When the button is clicked, setState('add-trip') runs, the component re-renders, and now the second condition is the true one.
If you only ever switch between two components, a ternary reads better:
{state === 'start' ? (
<AddTripButton addTrip={() => setState('add-trip')} />
) : (
<AnotherComponent />
)}
With more than two screens, the string-based approach scales nicely. Add a 'confirm' value, add another condition, done.
One thing to watch out for
When a component stops being rendered, React unmounts it. That means it loses its internal state.
Say AnotherComponent is a form with half-filled fields. If you switch back to 'start' and then to 'add-trip' again, the form remounts empty.
If you need those values to survive the switch, lift them up: keep the form data in the App component too, and pass it down as props. State that lives in a component that never unmounts doesn’t get lost.