reactjs React js嵌套路由强制useEffect在装载空数组([])后重新运行

62lalag4  于 2023-01-12  发布在  React
关注(0)|答案(1)|浏览(87)
import React, { useState, useEffect } from 'react';
import { Row, Col } from 'reactstrap';
import { Route, Switch, useLocation, useRouteMatch } from 'react-router-dom';

//components
import PatientSidebar from './PatientSidebar';
import PatientData from './PatientData';

//redux
import { useDispatch } from 'react-redux';
import { getAllPatients } from '../../store/actions';

const Patient = () => {
  const dispatch = useDispatch();
  const location = useLocation();
  let { path, url } = useRouteMatch(); // location={location} key={location.pathname}
  console.log(location);
  const [barWidth, setBarWidth] = useState();
  const [prevent, setPrevent] = useState('');

  /*This useEffect run when component is first mounted and it again runs when i select patient from sidebar (code is given below) to open its data using Link and nested routing*/
  useEffect(() => {
    dispatch(getAllPatients());
  }, [dispatch]);

  document.title = 'Patients';
  return (
    <React.Fragment>
      <div
        className='page-content ps-0 ps-md-3'
        style={{
          paddingLeft: '0',
          paddingTop: '70px',
          paddingRight: '0',
          // paddingBottom: '60px',
          overflow: 'hidden',
        }}
      >
        <Row>
          <Col
            xs={12}
            lg={3}
            style={{ paddingRight: '0', width: `${barWidth}px` }}
            className='position-relative toggle-patient-bar ps-0'
          >
            <PatientSidebar setBarWidth={setBarWidth} />
          </Col>
          <Switch>
            <Route
              render={() => <PatientData barWidth={barWidth}/>}
              exact
              path={`/patient/:id`}
              strict
            />
          </Switch>
        </Row>
      </div>
    </React.Fragment>
  );
};

export default Patient;

我有一个带有嵌套路由的父页面。问题是当我点击患者以使用react-router-domLink)在UI中打开其数据时,它强制重新安装此父组件,结果也强制重新运行useEffect,我真的不希望在此处发生这种情况。
注:它只发生在第一次选择的患者身上,如果我加载另一个患者,它不会重新安装父组件,并且一切正常,如预期。
这里是所有患者的侧条码:-在这里我发布了侧边栏的代码,如果我点击患者将其加载到嵌套的路线。

import React, { useEffect, useState, useRef } from 'react';
import { Button, Nav, NavItem, NavLink, TabContent, TabPane } from 'reactstrap';
import { Link, useRouteMatch } from 'react-router-dom';
import classnames from 'classnames';

//redux
import { useSelector, useDispatch } from 'react-redux';
import { showPatient, clearBills, loadMorePatients } from '../../store/actions';

//view hook
import useView from '../../Components/Hooks/UseView';

//loader
import Loader from '../../Components/Common/Loader';
import LoadMore from '../../Components/Common/LoadMore';

// let patients = ['Smith', 'Jack', 'Rose'];

const PatientSidebar = ({ setBarWidth }) => {
  let { path, url } = useRouteMatch();
  //search name
  const patient = useSelector((state) => state.viewPatient.patient);
  //get all patients
  const patients = useSelector((state) => state.getPatients.patients);
  //call redux action
  const dispatch = useDispatch();
  // Custom Tabs Bordered
  const [tHeight, setTHeight] = useState();
  const [customActiveTab, setcustomActiveTab] = useState('1');

  const toggleCustom = (tab) => {
    if (customActiveTab !== tab) {
      setcustomActiveTab(tab);
    }
  };

  const bar = useRef();
  const topRef = useRef();
  const headRef = useRef();
  const navsRef = useRef();
  useEffect(() => {
    if (window.innerWidth >= 1024) setBarWidth(bar.current.clientWidth); //1200
    setTHeight(
      parseInt(topRef.current.clientHeight) +
        parseInt(headRef.current.clientHeight) +
        parseInt(navsRef.current.clientHeight)
    );
  }, [window.innerWidth]);

  const toogleTab = () => {
    var windowSize = document.documentElement.clientWidth;
    if (windowSize < 1300) {
      document.documentElement.getAttribute('toogle-patient-tab') === 'sm'
        ? document.documentElement.setAttribute('toogle-patient-tab', 'lg')
        : document.documentElement.setAttribute('toogle-patient-tab', 'sm');
    }
  };

  const getPatient = (item) => {
    if (patient && patient._id !== item._id) {
      dispatch(clearBills());
      dispatch(showPatient(item));
    } else {
      dispatch(showPatient(item));
    }
  };

  return (
    <React.Fragment>
      <div
        ref={bar}
        className='patient-sidebar fancy-bar p-2 pt-3 position-fixed'
      >
        <div
          ref={topRef}
          className='d-flex justify-content-between align-items-center mt-2 mt-xl-0'
        >
          <h5 className='font-size-25 font-thin margin-bottom-0'>Patients</h5>
          <div className='d-flex'>
            <Button className='font-size-14 h-auto font-thin btn-primary btn-sm p-2 pt-1 pb-1'>
              Learn
            </Button>
            <div className='d-flex patient-menu-btn'>
              <button
                onClick={toogleTab}
                style={{ height: 'auto' }}
                type='button'
                className='btn btn-sm px-3 fs-16 header-item topnav-hamburger'
                id='topnav-hamburger-icon'
              >
                <span className='hamburger-icon'>
                  <span className='bg-dark'></span>
                  <span className='bg-dark'></span>
                  <span className='bg-dark'></span>
                </span>
              </button>

              {/* <SearchOption /> */}
            </div>
          </div>
        </div>
        <div className='toogle-patient-tab'>
          <h6 ref={headRef} className='font-size-14 font-thin mt-3'>
            Jagruti Rehabilitation Center - Taloja
          </h6>
          <div className='mt-3'>

            <TabContent}}
              activeTab={customActiveTab}
              className='text-muted'
            >
              <TabPane tabId='1' id='home1'>
                <div className='d-flex'>
                  <div className='flex-grow-1 ms-0'>
                    {(patients || []).map((item, idx) => {
                      return (
                        **<Link
                          to={`/patient/${item._id}`}
                          className='text-decoration-none text-secondary font-size-16'
                          key={item._id}
                        >
                          <div
                            key={idx}
                            style={{
                              borderColor:
                                patient && patient._id === item._id
                                  ? '#1e90ff'
                                  : '',
                            }}
                            className='p-2 patients border-bottom-1 d-flex align-items-center'
                            onClick={() => {
                              getPatient(item);
                              toogleTab();
                            }}
                          >
                            <img
                              className='rounded-circle avatar-xxs header-profile-user me-3 mt-0'
                              src={item.avatar}
                              alt='Patient Avatar'
                            />
                            <h3 className='text-decoration-none text-capitalize mb-0 text-secondary font-size-14'>
                              {item.firstName}
                            </h3>
                          </div>
                        </Link>**
                      );
                    })}
                    {!patients && (
                      <div className='text-center'>
                        <div
                          className='spinner-border text-primary me-3'
                          role='status'
                        >
                          <span className='visually-hidden'>Loading...</span>
                        </div>
                      </div>
                    )}
                    {patients && <LoadMore patients={patients} />}
                  </div>
                </div>
              </TabPane>
              <TabPane tabId='2'>
                <div className='d-flex'>
                  <div className='flex-grow-1 ms-0'></div>
                </div>
              </TabPane>
              <TabPane tabId='3'>
                <div className='d-flex'>
                  <div className='flex-grow-1 ms-0'></div>
                </div>
              </TabPane>
            </TabContent>
          </div>
        </div>
      </div>
    </React.Fragment>
  );
};

export default PatientSidebar;

我尝试了不同的方法来防止它,比如传递依赖数组,但我认为它的运行是由于组件重新挂载,所以真的没有工作。
组件,其中使用react延迟加载将所有路由导入和导出到index.js(呈现路由的根文件)。

import React, { lazy } from 'react';
import { Redirect } from 'react-router-dom';

//Dashboard
const Dashboard = lazy(() => import('../pages/Dashboard'));

//Client
const ViewPatients = lazy(() => import('../pages/ViewPatients/ViewPatients'));
const EditPatient = lazy(() => import('../pages/EditPatient/EditPatient'));
const AddUser = lazy(() => import('../pages/User/AddUser'));
const ViewAllUsers = lazy(() => import('../pages/User/ViewUsers'));
const EditUser = lazy(() => import('../pages/User/EditUser'));
const UsersLog = lazy(() => import('../pages/ActivityLog/UsersLog'));
const PatientsLog = lazy(() => import('../pages/ActivityLog/PatientsLog'));
const PatientLog = lazy(() => import('../pages/Patient/PatientLog'));
const ViewPatient = lazy(() =>
  import('../pages/Patient/ViewPatient/ViewPatient')
);
const Patient = lazy(() => import('../pages/Patient/Patient'));

//Reports
const Reports = lazy(() => import('../pages/Reports/Reports'));

//Quick Registration
const QuickRegistration = lazy(() =>
  import('../pages/QuickRegistration/QuickRegistration')
);
const DetailRegistration = lazy(() =>
  import('../pages/DetailRegistration/DetailRegistration')
);

//Authentication Inner pages
const ResetPassword = lazy(() =>
  import('../pages/ResetPassword/ResetPassword')
);

//login
const Login = lazy(() => import('../pages/Authentication/Login'));
const ForgetPassword = lazy(() =>
  import('../pages/Authentication/ForgetPassword')
);
const Logout = lazy(() => import('../pages/Authentication/Logout'));
const Register = lazy(() => import('../pages/Authentication/Register'));

// User Profile
const UserProfile = lazy(() => import('../pages/Authentication/user-profile'));
const Profile = lazy(() => import('../pages/Profile/Profile'));

// Settings
const AdvancePaymentSettings = lazy(() =>
  import('../pages/AdvancePaymentSettings/AdvancePaymentSettings')
);
const InvoiceSettings = lazy(() =>
  import('../pages/InvoiceSettings/InvoiceSettings')
);
const Settings = lazy(() => import('../pages/Settings/Setting'));

const authProtectedRoutes = [
  { path: '/dashboard', component: Dashboard },
  { path: '/index', component: Dashboard },

  //Client
  // { path: '/add-patient', component: AddPatient },
  { path: '/view-patients', component: ViewPatients },
  { path: '/edit-patient', component: EditPatient },
  { path: '/add-user', component: AddUser },
  { path: '/view-users', component: ViewAllUsers },
  { path: '/edit-user', component: EditUser },
  { path: '/users-log', component: UsersLog },
  // { path: "/patients-log", component: PatientsLog },
  { path: '/patient-log', component: PatientLog },
  // { path: '/view-patient', component: ViewPatient },
  { path: '/user-profile', component: Profile },
  //page where this issues occures -------------- start
  { path: '/patient', component: Patient },
  { path: '/patient/:id', component: Patient },
  //page where this issues occures -------------- end
  { path: '/quick-registration', component: QuickRegistration },
  { path: '/detail-registration', component: DetailRegistration },
  { path: '/settings', component: Settings },
  { path: '/advance-payment-settings', component: AdvancePaymentSettings },
  { path: '/invoice-settings', component: InvoiceSettings },
  { path: '/reports', component: Reports },
  { path: '/reset-password', component: ResetPassword },

  {
    path: '/',
    exact: true,
    component: () => <Redirect to='/login' />,
  },
];

const publicRoutes = [
  // Authentication Page
  { path: '/logout', component: Logout },
  { path: '/login', component: Login },
  { path: '/forgot-password', component: ForgetPassword },
  { path: '/register', component: Register },
];

export { authProtectedRoutes, publicRoutes };

所有路由的根index.js文件:

import React, { useEffect, Suspense } from 'react';
import { Switch, Route } from 'react-router-dom';

//Layouts
import NonAuthLayout from '../Layouts/NonAuthLayout';
import VerticalLayout from '../Layouts/index';
//routes
import { authProtectedRoutes, publicRoutes } from './allRoutes';
import { AuthProtected, AccessRoute } from './AuthProtected';

//load user
import { loadUser } from '../store/auth/actions/auth';
import { useDispatch } from 'react-redux';
import setAuthToken from '../utils/setAuthToken';

//import alerts
import Alerts from '../Components/Common/Alerts';

//loader
import Loader from '../Components/Common/LargeLoader';

// React Toastify
// import { ToastContainer, toast } from 'react-toastify';
// import 'react-toastify/dist/ReactToastify.css';

if (localStorage.token) {
  setAuthToken(localStorage.token);
}

const Index = () => {
  const dispatch = useDispatch();
  useEffect(() => {
    dispatch(loadUser());
  }, []);

  const availablePublicRoutesPaths = publicRoutes.map((r) => r.path);
  const availableAuthRoutesPath = authProtectedRoutes.map((r) => r.path);
  return (
    <React.Fragment>
      <Alerts />
      <Suspense fallback={<Loader />}>
        <Switch>
          <Route path={availablePublicRoutesPaths}>
            <NonAuthLayout>
              <Switch>
                {publicRoutes.map((route, idx) => (
                  <Route
                    path={route.path}
                    component={route.component}
                    key={idx}
                    exact={true}
                  />
                ))}
              </Switch>
            </NonAuthLayout>
          </Route>

          <Route path={availableAuthRoutesPath}>
            {/* <AuthProtected> */}
            <VerticalLayout>
              <Switch>
                {authProtectedRoutes.map((route, idx) => (
                  <AccessRoute
                    path={route.path}
                    component={route.component}
                    key={idx}
                    exact={true}
                  />
                ))}
              </Switch>
            </VerticalLayout>
            {/* </AuthProtected> */}
          </Route>
        </Switch>
      </Suspense>
    </React.Fragment>
  );
};

export default Index;
4zcjmb1e

4zcjmb1e1#

看起来你有一些事情对你不利。
1.所有Map的路由都指定了exact属性,因此这就是为什么删除"/patient/:id"会导致Patient在它是URL路径时不呈现。
1.该应用在两个不同的路径上呈现Patient,这两个路径只能“完全”匹配。
Patient组件正在将另一个"/patient/:id"路由呈现为派生路由,因此"/patient/:id"不需要同时作为渲染另一个Patient组件的根路由,需要记住的是Switch组件渲染第一个匹配的RouteRedirect组件。这意味着您应该按照与路由路径特定性相反的顺序列出路由,即"/:company/employees/:id""/:company/employees更特定比"/segment"更特定比"/"更特定。示例配置如下所示:

<Switch>
  <Route path="/:company/employees/:id" component={EmployeeDetail} />
  <Route path="/:company/employees" component={Employees} />
  <Route path="/:company" component={Company} />
  <Route path="/" exact component={Home} /> 
  <Route path="*" component={NotFound} />
</Switch>

如果更具体的路径与当前URL路径不匹配,则继续匹配不太具体的路径。如果排序正确,则几乎根本不需要exact属性。exact在上面的示例中用于 * 精确 * 匹配主页/登录页的"/"。但是在它上面或者通过主页/着陆页还没有匹配的任何内容将通过最终的“捕获全部”NotFound路径来呈现,即,类似于404页面。
在RRDv 5中需要考虑的另一件事是路径的作用更像是“路径前缀”。这意味着路径"/patient"可以匹配"/patient""/patient/:id"。这意味着根路由"/patient" * 的作用 * 更像"/patient*"
我建议重新排序配置数组中的路由,使其具有“正确的”路径特异性顺序。如果您需要精确匹配任何特定条目,请在此处指定exact属性,就像使用Redirect登录路由一样。path属性可以采用路径数组,因此对于呈现相同组件的路由,可以使用路径数组来匹配。2在数组中,按特性排序仍然很重要。
x一个一个一个一个x一个一个二个x

相关问题