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-dom
(Link
)在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;
1条答案
按热度按时间4zcjmb1e1#
看起来你有一些事情对你不利。
1.所有Map的路由都指定了
exact
属性,因此这就是为什么删除"/patient/:id"
会导致Patient
在它是URL路径时不呈现。1.该应用在两个不同的路径上呈现
Patient
,这两个路径只能“完全”匹配。Patient
组件正在将另一个"/patient/:id"
路由呈现为派生路由,因此"/patient/:id"
不需要同时作为渲染另一个Patient
组件的根路由,需要记住的是Switch
组件渲染第一个匹配的Route
或Redirect
组件。这意味着您应该按照与路由路径特定性相反的顺序列出路由,即"/:company/employees/:id"
比"/:company/employees
更特定比"/segment"
更特定比"/"
更特定。示例配置如下所示:如果更具体的路径与当前URL路径不匹配,则继续匹配不太具体的路径。如果排序正确,则几乎根本不需要
exact
属性。exact
在上面的示例中用于 * 精确 * 匹配主页/登录页的"/"
。但是在它上面或者通过主页/着陆页还没有匹配的任何内容将通过最终的“捕获全部”NotFound
路径来呈现,即,类似于404页面。在RRDv 5中需要考虑的另一件事是路径的作用更像是“路径前缀”。这意味着路径
"/patient"
可以匹配"/patient"
和"/patient/:id"
。这意味着根路由"/patient"
* 的作用 * 更像"/patient*"
。我建议重新排序配置数组中的路由,使其具有“正确的”路径特异性顺序。如果您需要精确匹配任何特定条目,请在此处指定
exact
属性,就像使用Redirect
登录路由一样。path
属性可以采用路径数组,因此对于呈现相同组件的路由,可以使用路径数组来匹配。2在数组中,按特性排序仍然很重要。x一个一个一个一个x一个一个二个x