I’m working on a React Native project where I have a custom Wizard component that allows users to navigate through different steps in a form. The Wizard component is used within a parent component like this:
<Wizard
activePage={activePage}
steps={[
{number: 1, title: 'Resume Header'},
{number: 2, title: 'Experience'},
{number: 3, title: 'Education'},
{number: 4, title: 'Skills and Details'},
]}
onStepPress={handleStepPress}
/>
he Wizard component handles the rendering of steps and allows navigation between them by clicking on step numbers. Now, I want to implement functionality where pressing the Android hardware back button will navigate to the previous step in the wizard (e.g., if the user is on step 2, pressing the back button should take them to step 1).
Here’s what I’ve tried:
To handle this, I added a backHandler function in the parent component and passed it down as a prop to the Wizard component. The parent component looks like this:
import React, { useState, useEffect } from 'react';
import { BackHandler } from 'react-native';
import Wizard from './Wizard';
const ParentComponent = () => {
const [activePage, setActivePage] = useState(1);
const handleStepPress = (pageNumber) => {
setActivePage(pageNumber);
return true;
};
const backAction = () => {
if (activePage > 1) {
handleStepPress(activePage - 1);
return true;
}
return false;
};
useEffect(() => {
const backHandler = BackHandler.addEventListener(
'hardwareBackPress',
backAction,
);
return () => backHandler.remove();
}, [activePage]);
return (
<Wizard
activePage={activePage}
steps={[
{ number: 1, title: 'Resume Header' },
{ number: 2, title: 'Experience' },
{ number: 3, title: 'Education' },
{ number: 4, title: 'Skills and Details' },
]}
onStepPress={handleStepPress}
backHandler={backAction} // Passed down to Wizard
/>
);
};
export default ParentComponent;
In the Wizard component, I added a listener for the hardware back button using the passed backHandler function:
import React, { useEffect, useState } from 'react';
import { View, Text, TouchableOpacity, StyleSheet, BackHandler } from 'react-native';
import { Colors } from '../styles/Colors';
interface WizardProps {
activePage: number;
steps: { number: number; title: string }[];
onStepPress: (pageNumber: number) => boolean;
backHandler: () => boolean;
}
const Wizard: React.FC<WizardProps> = ({ activePage, steps, onStepPress, backHandler }) => {
const [currentStep, setCurrentStep] = useState(activePage);
useEffect(() => {
setCurrentStep(activePage);
}, [activePage]);
useEffect(() => {
const backHandlerListener = BackHandler.addEventListener(
'hardwareBackPress',
backHandler,
);
return () => backHandlerListener.remove();
}, [currentStep, backHandler]);
return (
<View>
{/* Step rendering code */}
</View>
);
};
export default Wizard;
Problem:
This approach solves my problem, but I feel like it’s not the best practice. I had to modify the Wizard component to handle the back button, which seems unnecessary since the parent component should ideally manage this. I want to avoid disturbing the child component if it’s not necessary.
Expected Solution:
Is there a better way to handle the hardware back button in the parent component without having to modify the Wizard component? I’m looking for a solution that keeps the Wizard component generic and reusable without being tightly coupled to the back button logic.