简体   繁体   English

React-Router - 路由更改时的路由重新渲染组件

[英]React-Router - Route re-rendering component on route change

Please read this properly before marking as duplicate, I assure you I've read and tried everything everyone suggests about this issue on stackoverflow and github.请在标记为重复之前正确阅读此内容,我向您保证我已经阅读并尝试了每个人在 stackoverflow 和 github 上提出的有关此问题的所有建议。

I have a route within my app rendered as below;我的应用程序中有一条路线呈现如下;

<div>
        <Header compact={this.state.compact} impersonateUser={this.impersonateUser} users={users} organisations={this.props.organisations} user={user} logOut={this.logout} />
        <div className="container">
            {user && <Route path="/" component={() => <Routes userRole={user.Role} />} />}
        </div>
    {this.props.alerts.map((alert) =>
            <AlertContainer key={alert.Id} error={alert.Error} messageTitle={alert.Error ? alert.Message : "Alert"} messageBody={alert.Error ? undefined : alert.Message} />)
        }
    </div>

The route rendering Routes renders a component that switches on the user role and lazy loads the correct routes component based on that role, that routes component renders a switch for the main pages.路由渲染Routes渲染一个组件,该组件在用户角色上切换,并根据该角色延迟加载正确的路由组件,该路由组件为主页呈现一个开关。 Simplified this looks like the below.简化后如下所示。

import * as React from 'react';
import LoadingPage from '../../components/sharedPages/loadingPage/LoadingPage';
import * as Loadable from 'react-loadable';

export interface RoutesProps {
    userRole: string;
}

const Routes = ({ userRole }) => {

var RoleRoutesComponent: any = null;
switch (userRole) {
    case "Admin":
        RoleRoutesComponent = Loadable({
            loader: () => import('./systemAdminRoutes/SystemAdminRoutes'),
            loading: () => <LoadingPage />
        });
        break;
    default:
        break;
}

return (
    <div>
        <RoleRoutesComponent/> 
    </div>
);

}

export default Routes;

And then the routes component然后路由组件

const SystemAdminRoutes = () => {

var key = "/";

return (
    <Switch>
        <Route key={key} exact path="/" component={HomePage} />
        <Route key={key} exact path="/home" component={HomePage} />
        <Route key={key} path="/second" component={SecondPage} />
        <Route key={key} path="/third" component={ThirdPage} />
        ...
        <Route key={key} component={NotFoundPage} />
    </Switch>
);
}

export default SystemAdminRoutes;

So the issue is whenever the user navigates from "/" to "/second" etc... app re-renders Routes , meaning the role switch logic is rerun, the user-specific routes are reloaded and re-rendered and state on pages is lost.所以问题是每当用户从“/”导航到“/second”等...应用程序重新渲染Routes ,这意味着重新运行角色切换逻辑,重新加载和重新渲染用户特定的路由并在页面上显示丢失了。

Things I've tried;我尝试过的事情;

  • I've tried this with both react-loadable and React.lazy() and it has the same issue.我已经用 react-loadable 和React.lazy()尝试过这个,它有同样的问题。
  • I've tried making the routes components classes我试过制作路由组件类
  • Giving all Routes down the tree the same key给树下的所有路由相同的密钥
  • Rendering all components down to the switch with path "/" but still the same problem.将所有组件渲染到带有路径“/”的开关,但仍然存在相同的问题。
  • Changing Route's component prop to render.更改 Route 的组件属性以进行渲染。
  • Changing the main app render method to component={Routes} and getting props via redux将主应用程序渲染方法更改为component={Routes}并通过 redux 获取道具
  • There must be something wrong with the way I'm rendering the main routes component in the app component but I'm stumped, can anyone shed some light?我在应用程序组件中渲染主要路由组件的方式一定有问题,但我很困惑,有人能解释一下吗? Also note this has nothing to do with react-router's switch.另请注意,这与 react-router 的开关无关。

    EDIT: I've modified one of my old test project to demonstrate this bug, you can clone the repo from https://github.com/Trackerchum/route-bug-demo - once the repo's cloned just run an npm install in root dir and npm start.编辑:我已经修改了我的一个旧测试项目来演示这个错误,你可以从https://github.com/Trackerchum/route-bug-demo克隆 repo - 一旦 repo 被克隆,只需在 root 中运行 npm install dir 和 npm start。 I've got it logging to console when the Routes and SystemAdminRoutes are re-rendered/remounted当 Routes 和 SystemAdminRoutes 重新渲染/重新安装时,我已将其记录到控制台

    EDIT: I've opened an issue about this on GitHub, possible bug编辑:我已经在 GitHub 上打开了一个关于这个的问题,可能是错误

    Route re-rendering component on every path change, despite path of "/"尽管路径为“/”,但在每次路径更改时路由重新渲染组件

    Found the reason this is happening straight from a developer (credit Tim Dorr).直接从开发人员那里找到了发生这种情况的原因(感谢 Tim Dorr)。 The route is re-rendering the component every time because it is an anonymous function.路由每次都重新渲染组件,因为它是一个匿名函数。 This happens twice down the tree, both in App and Routes (within Loadable function), below respectively.这在树下发生两次,分别在 App 和 Routes(在 Loadable 函数内),分别如下。

    <Route path="/" component={() => <Routes userRole={user.Role} />} />
    

    needs to be需要是

    <Routes userRole={user.Role} />
    

    and

    loader: () => import('./systemAdminRoutes/SystemAdminRoutes')
    

    Basically my whole approach needs to be rethought基本上我的整个方法需要重新思考

    EDIT: I eventually fixed this by using the render method on route:编辑:我最终通过在路由上使用渲染方法解决了这个问题:

    <Route path="/" render={() => <Routes userRole={user.Role} />} />
    

    Bumped into this problem and solved it like this:碰到这个问题并解决它是这样的:

    In the component:在组件中:

    import {useParams} from "react-router-dom";
        
    const {userRole: roleFromRoute} = useParams();
    const [userRole, setUserRole] = useState(null);
    
    
    useEffect(()=>{
        setUserRole(roleFromRoute);
    },[roleFromRoute]}
    

    In the routes:在路线中:

    <Route path="/generic/:userRole" component={myComponent} />
    

    This sets up a generic route with a parameter for the role.这将使用角色的参数设置通用路由。

    In the component useParams picks up the changed parameter und the useEffect sets a state to trigger the render and whatever busines logic is needed.在组件中 useParams 获取更改的参数,并且 useEffect 设置一个状态以触发渲染以及需要的任何业务逻辑。

    },[userRole]); },[用户角色]);

    Just put the "/" in the end and put the other routes above it.只需将“/”放在最后并将其他路线放在其上方。 Basically it's matching the first available option, so it matches "/" every time.基本上它匹配第一个可用选项,所以它每次都匹配“/”。

    <Switch>
            <Route key={key} exact path="/home" component={HomePage} />
            <Route key={key} path="/second" component={SecondPage} />
            <Route key={key} path="/third" component={ThirdPage} />
            <Route key={key} exact path="/" component={HomePage} />
            <Route key={key} component={NotFoundPage} />
    </Switch>
    
    OR
    
    <Switch>
              <Route path="/second" component={SecondPage} />
              <Route exact path="/" component={HomePage} />
              <Route path="*" component={NotFound} />
    </Switch>
    

    Reorder like this, it will start working.像这样重新排序,它将开始工作。 Simple :)简单的 :)

    声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

     
    粤ICP备18138465号  © 2020-2024 STACKOOM.COM