Home > Back-end >  Why with history.push onClick function I have two components rendered insted of one which I wanted?
Why with history.push onClick function I have two components rendered insted of one which I wanted?

Time:11-23

I have a situation where on onClick funtion which should push to path :'/trains/alerts-list' which actually happens but it renders under this url component TrainAlertsList which is correct, but below it's rendering also TrainDetailsScreen which is not correct. I have onClick function like below :

enter image description here

Which creates url path of TrainsListAlerts:

TrainsAlertsList: {
        path: '/trains/alerts-list',
        name: 'Trains alerts list',
        viewName: 'TRAINS_ALERTS_LIST',
    },
TrainDetails: {
        path: '/trains/:idTrain',
        name: 'Train details',
        viewName: 'TRAIN_DETAILS',
    },

routingManager.tsx file looks like:

const TrainsAlertsListScreen = lazy(() =>
    import('@nevomo/trains').then((module) => ({
        default: module.TrainsAlertsList,
    }))

const TrainDetailsScreen = lazy(() =>
    import('@nevomo/trains').then((module) => ({
        default: module.TrainDetailsScreen,
    }))
);
<ProtectedRoute
                    requiredRoles={[
                        ROLES.vehicleOperator,
                        ROLES.vehicleAnalyst,
                    ]}
                    isAuth={isLogin}
                    exact
                    path={[
                        Routes.Trains.path,
                        Routes.TrainsMap.path,
                        Routes.TrainDetails.path,
                        Routes.TrainHistory.path,
                        Routes.TrainService.path,
                        Routes.TrainWheels.path,
                        Routes.TrainsAlertsList.path,
                    ]}
                >
);

<ProtectedRoute
                            requiredRoles={[
                                ROLES.vehicleOperator,
                                ROLES.vehicleAnalyst,
                            ]}
                            isAuth={isLogin}
                            path={Routes.TrainsAlertsList.path}
                            Component={TrainsAlertsListScreen}
                            exact
                        />
                        <ProtectedRoute
                            requiredRoles={[
                                ROLES.vehicleOperator,
                                ROLES.vehicleAnalyst,
                            ]}
                            isAuth={isLogin}
                            path={Routes.TrainDetails.path}
                            Component={TrainDetailsScreen}
                            exact
                        />

index.ts with all exports:

export * from './lib/trains';
export * from './lib/components/map/map';
export * from './views/train-details/train-details';
export * from './views/train-history/train-history';
export * from './views/train-service/train-service';
export * from './views/train-wheels/train-wheels';
export * from './views/train-wheels/components/train-wheels-details/train-wheels-details';
export * from './views/train-wheels/components/train-wheels-faults/train-wheels-faults';
export * from './lib/components/trains-alerts-list/trains-alerts-list';

And component:

import { Toolbar } from '@nevomo/common-components'; import { FC } from 'react';

export const TrainsAlertsList: FC = () => {
    return (
        <div>
            <Toolbar />
            <div>działa</div>
        </div>
    );
};

Can You please look at it and let me know what is causing that TrainDetailsScreen is rendered although it's not called ? And how to fix it ?

thanks a lot !

CodePudding user response:

These 2 routes match the same thing. /trains/alerts-list is the same as trains/:id or use the exact attribute in the Route component (This is not the case if you are using react-router v6). You should change one of them. Try with trains/:id/details

TrainsAlertsList: {
        path: '/trains/alerts-list',
        name: 'Trains alerts list',
        viewName: 'TRAINS_ALERTS_LIST',
    },
TrainDetails: {
        path: '/trains/:idTrain',
        name: 'Train details',
        viewName: 'TRAIN_DETAILS',
    },

CodePudding user response:

Both these components match and render on the Routes.TrainDetails.path (i.e. "/trains/:idTrain") path. Since both are being rendered then I'll assume you are rendering your routes into a Router and not within a Switch. If you are wanting only a single route to match and be rendered render them into the Switch component.

Switch

The Switch differs from the Router in that a Router inclusively renders all matching routes by path whereas the Switch exclusively renders only the first match. In the Switch path order and specificity matter! You want to order the paths from more specific paths to less specific, so matching and rendering can work properly.

'/trains/alerts-list' is more specific than '/trains/:idTrain' and should be rendered higher/before.

Example:

<Router>

  ...

  <Switch>

    .... other more specific "/trains/alerts-list/...." routes

    <ProtectedRoute
      requiredRoles={[
        ROLES.vehicleOperator,
        ROLES.vehicleAnalyst,
      ]}
      isAuth={isLogin}
      path={Routes.TrainsAlertsList.path} // '/trains/alerts-list'
      Component={TrainsAlertsListScreen}
    />

    .... other more specific "/trains/...." routes

    <ProtectedRoute
      requiredRoles={[
        ROLES.vehicleOperator,
        ROLES.vehicleAnalyst,
      ]}
      isAuth={isLogin}
      path={Routes.TrainDetails.path}     // '/trains/:idTrain'
      Component={TrainDetailsScreen}
    />

    .... other less routes

  </Switch>

  ...

</Router>
  • Related