-1

I am fairly new to React and am having trouble having a component load when my URL changes.

As a little background, I am using Fireact (https://www.fireact.dev/) as a starting point for this project. What I am trying to do is dynamically load a page with two parameters (accountId and analyticsID). The URL sucesffully changes from /account/QQAH7q5Iz1gwOvpJ4WlA/Analytics to http://localhost:3000/account/QQAH7q5Iz1gwOvpJ4WlA/Analytics/NebYvepZw8IFWmWugPHBbut the target component doesn't load (AnalyticsFeatureView). The target component (AnalyticsFeatureView) does load if I debug this to the root route so it doesn't appear to be an error with the target component. Could this have to do with having two parameters within the App.Js file loading <AuthRouter path="/account/:accountId/:path?" component={Feature} template={AccountTemplate} title="Feature" role="*" /> or something like that?

Please let me know any other information you need.

I currently have the following code snippets between what I believe to be the four relevant files:

  • App.js
import React from 'react';
import { BrowserRouter as Router, Switch } from "react-router-dom";
import { AuthProvider } from './components/FirebaseAuth';

import PublicRouter from './components/routers/PublicRouter';
import PublicTemplate from './components/templates/PublicTemplate';
import AccountTemplate from './components/templates/AccountTemplate';

import AuthRouter from './components/routers/AuthRouter';

import SignIn from './pages/public/SignIn';
import Home from './pages/auth/Home';
import PageNotFound from './pages/public/PageNotFound';
import AppTemplate from './components/templates/AppTemplate';
import UserProfile from './pages/auth/user/UserProfile';
import UpdateEmail from './pages/auth/user/UpdateEmail';
import UpdateName from './pages/auth/user/UpdateName';
import VerifyEmail from './pages/auth/user/VerifyEmail';
import UpdatePassword from './pages/auth/user/UpdatePassword';
import UpdatePhone from './pages/auth/user/UpdatePhone';
import DeleteUser from './pages/auth/user/DeleteUser';
import ViewLogs from './pages/auth/user/ViewLogs';
import Plans from './pages/auth/accounts/Plans';
import NewAccount from './pages/auth/accounts/NewAccount';


// load stripe
import stripeJson from "./inc/stripe.json";
import { Elements } from '@stripe/react-stripe-js';
import { loadStripe } from '@stripe/stripe-js';
import { Feature } from './pages/auth/accounts/Feature';
import UserList from './pages/auth/accounts/UserList';
import UserRole from './pages/auth/accounts/UserRole';
import AddUser from './pages/auth/accounts/AddUser';
import Invite from './pages/auth/user/Invite';
import PaymentList from './pages/auth/accounts/PaymentList';
import PaymentMethod from './pages/auth/accounts/PaymentMethod';
import DeleteAccount from './pages/auth/accounts/DeleteAccount';

import AnalyticsView from './features/fireact-demo-feature-main/AnalyticsFeatureView';




const stripePromise = loadStripe(stripeJson.stripeConfig.public_api_key);



function App() {
    return (
        <Elements stripe={stripePromise}>
            <AuthProvider>
                <Router>
                    <Switch>
                        <AuthRouter exact path="/" component={Home} template={AppTemplate} title="My Accounts" />
                        <AuthRouter exact path="/account/:accountId/billing/plan" component={Plans} template={AccountTemplate} title="Select Plan" role="admin" allowInactive={true} />
                        <AuthRouter exact path="/account/:accountId/billing/payment-method" component={PaymentMethod} template={AccountTemplate} title="Update Payment Method" role="admin" />
                        <AuthRouter exact path="/account/:accountId/billing/delete" component={DeleteAccount} template={AccountTemplate} title="Delete Account" role="admin" />
                        <AuthRouter exact path="/account/:accountId/users/change/:userId" component={UserRole} template={AccountTemplate} title="Change Role" role="admin" />
                        <AuthRouter exact path="/account/:accountId/users" component={UserList} template={AccountTemplate} title="Users" role="admin" />
                        <AuthRouter exact path="/account/:accountId/users/add" component={AddUser} template={AccountTemplate} title="Add User" role="admin" />
                        <AuthRouter exact path="/account/:accountId/billing" component={PaymentList} template={AccountTemplate} title="Billing" role="admin" />
                        <AuthRouter eact path="/account/:accountId/Analytics/:analyticsId" component={Feature} template={AccountTemplate} title="Feature" role="*" />
                        <AuthRouter path="/account/:accountId/:path?" component={Feature} template={AccountTemplate} title="Feature" role="*" />
                        
                        <AuthRouter exact path="/new-account" component={NewAccount} template={AppTemplate} title="Create New Account" />
                        <AuthRouter exact path="/user/profile" component={UserProfile} template={AppTemplate} title="User Profile" />
                        <AuthRouter exact path="/invite/:code" component={Invite} template={AppTemplate} title="View Invite" />
                        <AuthRouter exact path="/user/profile/update-email" component={UpdateEmail} template={AppTemplate} title="Change Your Email" />
                        <AuthRouter exact path="/user/profile/update-name" component={UpdateName} template={AppTemplate} title="Change Your Name" />
                        <AuthRouter exact path="/user/profile/verify-email" component={VerifyEmail} template={AppTemplate} title="Verify Your Name" />
                        <AuthRouter exact path="/user/profile/update-password" component={UpdatePassword} template={AppTemplate} title="Change Your Password" />
                        <AuthRouter exact path="/user/profile/update-phone" component={UpdatePhone} template={AppTemplate} title="Change Your Phone Number" />
                        <AuthRouter exact path="/user/profile/delete" component={DeleteUser} template={AppTemplate} title="Delete Your Account" />
                        <AuthRouter exact path="/user/log" component={ViewLogs} template={AppTemplate} title="View Activity Logs" />
                        <PublicRouter exact path="/signin" component={SignIn} template={PublicTemplate} title="Sign In" />
                        <PublicRouter component={PageNotFound} template={PublicTemplate} title="Page Not Found" />
                    </Switch>
                </Router>
            </AuthProvider>
        </Elements>
    );
}

export default App;

  • FeatureRoutes.js
import React from 'react';
import { Route, Switch, useParams } from "react-router-dom";
import Home from '.';
import ModelsTable from './ModelsNew';
import TemplatesTable from './TemplatesNEW';
import Analytics from './AnalyticsFeature';
import NewModel from './NewModel';
import AnalyticsView from './AnalyticsFeatureView';


const FeatureRoutes = () => {
    const { accountId, analyticsID } = useParams();

    return (
        <Switch key="demo">


            <Route path={'/account/' + accountId + '/Analytics/' + analyticsID} >
                <AnalyticsView />
            </Route>

            <Route path={'/account/' + accountId +'/templates'}>
                <TemplatesTable />
            </Route>


            <Route path={'/account/' + accountId +'/Models'} >
                <ModelsTable />
            </Route>
            <Route path={'/account/' + accountId + '/Model/New'} >
                <NewModel />
            </Route>

            <Route path={'/account/' + accountId + '/Analytics'} >
                <Analytics />
            </Route>

            <Route path={'/account/' + accountId + '/testing'} role="admin">
                <TemplatesTable />
            </Route>
            <Route>
                <Home />
            </Route>
        </Switch>
    )
}

export default FeatureRoutes;
  • AnalyticsFeature.js
import React, { useState, useContext, useEffect, useRef } from "react";
import { BreadcrumbContext } from '../../components/Breadcrumb';
import { FirebaseAuth } from "../../components/FirebaseAuth/firebase";
import { useHistory, Redirect, useParams } from 'react-router-dom';
import Loader from '../../components/Loader';
import DataTable from "../../components/DataTable";
import { Card, Button, CardActions, Grid, CardHeader } from "@mui/material";
import { AuthContext } from "../../components/FirebaseAuth";
import { CloudFunctions } from "../../components/FirebaseAuth/firebase";

const Analytics = () => {
    const title = 'Analytics';
    const history = useHistory();
    const { userData } = useContext(AuthContext);
    const { setBreadcrumb } = useContext(BreadcrumbContext);
    const [loading, setLoading] = useState(true);
    const [accounts, setAccounts] = useState([]);
    const mountedRef = useRef(true);

    const showAnalytics = () => {
        setLoading(true);
        let records = [];
        //const accountsRef = FirebaseAuth.firestore().collection('accounts');
        //let query = accountsRef.where('access', 'array-contains', FirebaseAuth.auth().currentUser.uid);

        const getAnalytics = CloudFunctions.httpsCallable('getAnalytics');
        getAnalytics({
            accountId: userData.currentAccount.id
        }).then(accountSnapshots => {
            if (!mountedRef.current) return null
            accountSnapshots.data.forEach(account => {
                records.push({
                    'id': account.id,
                    'analyticsName': account.name,
                    'analyticsDescription': account.description,
                    'analyticsURL': account.url
                });
            });
            setAccounts(records);
            setLoading(false);
        });
    }

    useEffect(() => {
        setBreadcrumb([
            {
                to: "/",
                text: "Home",
                active: false
            },
            {
                to: "/account/" + userData.currentAccount.id + "/",
                text: userData.currentAccount.name,
                active: false
            },
            {
                to: null,
                text: title,
                active: true
            }
        ]);
        showAnalytics();
    }, [userData, setBreadcrumb, history]);

    useEffect(() => {
        return () => {
            //mountedRef.current = false
        }
    }, []);


    //~~~~~~~~~THE BELOW NEEDS LOADING INDICATORS
    return (
        <>
                    <div style={{ marginTop: '20px', marginBottom: '20px', textAlign: 'right' }}>
                        <Button variant="contained" onClick={() => history.push("/account/" + userData.currentAccount.id + "/Analytics/New")}><i className="fa fa-plus"></i>Add Report</Button>
                    </div >
                    <Grid item xs={12} container spacing={4}>
                        {accounts.map((account, i) =>
                            <Grid container item xs={12} md={12} key={i}>
                                <Card key={account.id} style={{ width: '25%' }}>
                                    <CardHeader title={account.analyticsName} />
                                    <div padding-left='30px'>
                                        {account.analyticsDescription} <br /><br />
                                        {userData.currentAccount.id}<br /><br />
                                        {account.id }
                                    </div>
                                    <CardActions>
                                        <Button size="small" color="primary" onClick={() => history.push('/account/' + userData.currentAccount.id + '/Analytics/' + account.id)}>View Report</Button>
                                        </CardActions>
                                </Card>
                            </Grid>
                        )}
            </Grid>
        </>

    )
}
export default Analytics;
  • Feature.js
import { Chip } from "@mui/material";
import React, { useContext, useEffect, Suspense, useState } from "react";
import { BreadcrumbContext } from '../../../../components/Breadcrumb';
import { AuthContext } from "../../../../components/FirebaseAuth";
import Loader from "../../../../components/Loader";

const components = [];
  
// Here: catch and return another lazy (promise)
const requireComponents = require.context(
    '../../../../features', // components folder
    true, // look subfolders
    /\w+\/FeatureRoutes\.(js)$/ //regex for files
);
requireComponents.keys().forEach((filePath) => {
    const folder = filePath.split("/")[1];
    const name = filePath.split("/")[2];
    const Feature = React.lazy(() =>
    import("../../../../features/" + folder + "/" + name));
    components.push(<Feature key={components.length+1} />);
});

export const titleContext = React.createContext();

export const Feature = () => {
    const [ title, setTitle ] = useState("Default Feature");

    const { userData } = useContext(AuthContext);
    const { setBreadcrumb } = useContext(BreadcrumbContext);
    
    useEffect(() => {
        setBreadcrumb([
            {
                to: "/",
                text: "Home",
                active: false
            },
            {
                to: "/account/"+userData.currentAccount.id+"/",
                text: userData.currentAccount.name,
                active: false
            },      
            {
                to: null,
                text: title,
                active: true
            }
        ]);
    }, [userData, setBreadcrumb, title]);

    return (
        <>
            {(components.length > 0)?(
                <titleContext.Provider value={{title, setTitle}} >
                    <Suspense fallback={<Loader />}>
                        {components}
                    </Suspense>
                </titleContext.Provider>
            ):(
                <>
                    <div>This is the default feature</div>
                </>
            )}
        </>

    )
}

I have tried creating different route patterns within the App.Js and FeatureRouter.js files. I have also successfully loaded the target component within the root directory.

Drew Reese
  • 165,259
  • 14
  • 153
  • 181
kfk103
  • 1
  • 2
  • What ***specific*** versions of `react` and `react-router-dom` are installed? Check by running `npm list react react-router-dom`. Are you using `react@18`, some `react-router-dom@5` version, and rendering the app into a `React.StrictMode` component by any chance? Does this help answer your question? https://stackoverflow.com/a/71833424/8690857 If this doesn't then please [edit] to more clearly explain what exactly the issue is, including reproduction steps. – Drew Reese Feb 19 '23 at 21:04

1 Answers1

0

FYI - For the offchance that someone is having this error.

  1. I added a new folder called "analytics" and file titled "FeatureRoutes".

  2. I added the following code to the "FeatureRoutes"

    import React from 'react';
    import { Route, Switch, useParams } from "react-router-dom";
    import AnalyticsView from './AnalyticsFeatureView';


    const FeatureRoutes = () => {
        const { accountId, analyticsID } = useParams();

        return (
            <Switch key="demo">


                <Route exact path={'/account/:accountId/Analytics/:analyticsID'} >
                    <AnalyticsView />
                </Route>
            </Switch>
        )
    }

    export default FeatureRoutes;
  1. Added my "AnalyticsFeatureView" component to the "analytics" folder
Moritz Ringler
  • 9,772
  • 9
  • 21
  • 34
kfk103
  • 1
  • 2