0

We're currently developing implementing a wizard in React Native application using Atomic Design (Pages, Templates, Organisms, Molecules, Atoms), and React Navigation.

The wizard will have a progress bar that must be present on every screen. We are facing a structure challenge. How should we create and develop the children components?

We have thought of 2 approaches:

  1. We create a "Layout" template component that will handle the progress bar, instantiate this component in an Atomic Design Page and pass a children into it. We change each page using a navigation. This violates the Page principle, which should be instantiated a simple Template and pass information to it.

  2. We create a "Master Layout" which conditionally renders the required UI. This is controlled through a context in which children components update. This one does not have cross-cutting concerns. But one of our teammembers is concerned that it hides the implementation from the children (Note that children return <></> empty.

Here's the date of birth page that better describes it:

  • The green bounding box represents the "Layout" on 1. and the "Master Layout" on 2.
  • The orange bounding box is the content that changes across each wizard step.

Note that both approaches render the same UI.

Approach 1:

// pages/UpdateProfileDOB/index.tsx
// This has cross-cutting concerns and injects an Organism (UpdateProfileDOB) inside the 
// OnboardingStepTemplate (Template)
export const UpdateProfileDOBPage: FC = () => {
    const { updateProfile, defaultInitialValues, loading } =
        useUpdateOnboardingProfile();

    return (
        <OnboardingStepTemplate
            title={t`What’s your birth date?`}
            loading={loading}
            progress={20}>
            <UpdateProfileDOBForm
                initialValues={defaultInitialValues}
                handleSubmit={updateProfile}
            />
        </OnboardingStepTemplate>
    );
};

Approach 2:

// pages/OnboardingUpdateDOBPage/index.tsx
// This doesn't have cross-cutting concerns, and uses a hook to update the parent
// This hook is rendered through a context.
// It returns a Fragment.
export const OnboardingUpdateDOBPage: FunctionComponent = props => {
    const { updateProfile, defaultInitialValues, loading } =
        useUpdateOnboardingProfile();

    useOnboardingBuilder({
        title: t`What's your birth date?`,
        progress: 20,
        loading,
        builder: {
            onSubmit: updateProfile,
            validationSchema: updateDOBValidationSchema,
            initialValues: {
                dateOfBirth: defaultInitialValues.dateOfBirth || new Date(),
            },
            submitText: t`Continue`,
            fields: [
                {
                    name: 'dateOfBirth',
                    type: 'date',
                    label: t`Date of Birth`,
                },
            ],
        },
    });
    return <></>;
};

Here's the wizard approach #1:

// We take advantage of React Navigator and use `useNavigate()`
// to move between the wizards.
            <OnboardingStack.Navigator
                screenOptions={{
                    headerShown: false,
                }}
                initialRouteName={pageName}>
                <OnboardingStack.Screen
                    name={Routes.SCREEN1}
                    component={OnboardingUpdateProfileName}
                />
                <OnboardingStack.Screen
                    name={Routes.SCREEN2}
                    component={OnboardingUpdateDOBPage}
                />
               
            </OnboardingStack.Navigator>

Here's the wizard approach #2:

// We take advantage of React Navigator and use `useNavigate()`
// to move between the wizards.
// 
// Note: OnboardingStepV2Template wraps the Navigator and provides it with 
// a context.
 <OnboardingStepV2Template loading={loading}>
            <OnboardingStack.Navigator
                screenOptions={{
                    headerShown: false,
                }}
                initialRouteName={pageName}>
                <OnboardingStack.Screen
                    name={Routes.SCREEN1}
                    component={OnboardingUpdateProfileName}
                />
                <OnboardingStack.Screen
                    name={Routes.SCREEN2}
                    component={OnboardingUpdateDOBPage}
                />
               
            </OnboardingStack.Navigator>
        </OnboardingStepV2Template>

Additional note

  • I believe react navigation is overkill and it can be modeled using a simple context rendering.

What do you think?

Jose A
  • 275
  • 3
  • 12

0 Answers0