使用 react-router-dom 停止页面中侧边栏的重新渲染

Posted

技术标签:

【中文标题】使用 react-router-dom 停止页面中侧边栏的重新渲染【英文标题】:Stop the re-rendering of Sidebar in Page using react-router-dom 【发布时间】:2020-07-19 22:54:55 【问题描述】:

任何帮助将不胜感激,所以我有一个带有页眉、侧边栏、页脚和主页面的页面,其中侧边栏有静态链接,单击时会显示组件。这里的问题是单击链接,侧边栏,页眉和页脚正在重新渲染,这不是必需的。我在侧边栏中尝试了 shouldComponentUpdate 但它不起作用。 项目使用的版本: “反应”:“^16.12.0”, “反应域”:“^16.12.0”, "react-router-dom": "^5.1.2", 我会一直在这里,直到这个问题得到解决,所以请随时提出任何问题

这里是 myApp.js(根文件)

function App() 
  return (
    <Provider store=Store>
        <Router history=history>              
            <AppRoutes />
          </Router>             
    </Provider>
  );

现在 AppRoutes 组件有以下方法

const RouteList = [
    
        path: "/",
        component: Dashboard,
        guest: false,
        exact: true
    ,
    
        path: "/security_info",
        component: SecurityInfoPage,
        guest: false,
        exact: true
    ,
]

class AppRoutes extends Component 

    componentDidMount() 
        ...here we fetch the login info from store
        isAuthenticated = true
       

    render() 
        ...if it has access token, it 
        return (
            <Switch>
                RouteList.map((route, i) => (
                    route.guest === false 
                    ? <PrivateRoute isAuthenticated=isAuthenticated key=i ...route /> 
                    : <AppRoute key=i ...route />
                    )
                )
            </Switch>
        );
    

因为 is_authenticated 为真,所以它转到 AppRoute.js 文件中的私有路由

const PrivateRoute = (isAuthenticated,  component: Component, ...rest ) => (
   <Route 
        ...rest 
        render=(props) => (
            isAuthenticated === true
              ? <DashboardLayout>
                            <Component ...props/>
                        </DashboardLayout>
              : <Redirect to='/login' />
        ) 
    />
)

它转到具有多个组件的仪表板布局

<div className='wrapper'>
                <Navigation />
                <div className="page-content">
                    <Sidebar />
                    <div className="content-wrapper">
                        children
                        <MessageSideBar />
                        <Footer />
                    </div>
                </div>
            </div>

现在,当我单击不同的链接时,它会转到仪表板布局,其中其道具子项会发生更改,从而呈现整个仪表板,包括页眉、页脚、侧边栏。 编辑1: 这是侧边栏文件

class Sidebar extends Component 

componentDidMount = () => 
        it is requesting data from 3 api's
        this.props.dispatch(sidebarAction.sidebarDetail())
        this.props.dispatch(settingAction.getCreditAmount())
        this.props.dispatch(messageAction.getUnReadMessageCount())
    
render()
return(
   <ul>
    <li>
     <NavLink 
        exact=true 
        to="/" >
        <span>Dashboard</span>
     </NavLink>
    </li>
    <li>
      <NavLink to="/security_info">
        <span>Security Information</span>
      </NavLink>
    </li>
   </ul>
)

虽然有 10 多个 NavLink,但我只包含了 2 个并且还删除了不相关的类名

【问题讨论】:

如果我是你,我会尝试为那些依赖于经过身份验证的用户的组件创建条件渲染。如果 auth bool 为 true,则显示这些组件(侧边栏、标题按钮等)。我不会让整个布局依赖于 auth 布尔值,只是那些实际上依赖于它的布局。您可以为此使用上下文 API 或 redux。另一种选择是对这些元素使用纯组件,这样它们就不会重新渲染,除非 auth bool 发生变化。 请将代码贴在您创建链接的地方,即侧边栏。 @Rodrigo 先生,我不知道 Context API 以及如何使用纯组件,我正在寻找一种方法来停止重新渲染。 纯组件允许您在父组件重新渲染但子组件的 prop 或状态值不重新渲染时避免重新渲染:reactjs.org/docs/react-api.html#reactpurecomponent 在这里您可以阅读有关 Context API 的信息: reactjs.org/docs/context.html 你也可以看看这个:reactjs.org/docs/conditional-rendering.html 【参考方案1】:

方法不对

您的路由的结构类似于以下 sn-p,这将导致每次切换路由时重新渲染 Dashboard 组件。

<Route path="/subComponent" component=SubComponent/>
const SubComponent = () => 
    return (
        <Dashboard>
            // Here is your content place
        </Dashboard>
    )

正确方法

但是,正确的解决方案是将路由直接放在Dashboard 组件中,您希望在其中呈现由布局 (Dashboard) 包裹的组件,如下所示:

<Dashboard>
    <DashboardMenu>
        <SideNav /> // e.g. containing links with history.push()
    </DashboardMenu>

    // here is the place where the components wrapped by the layout should be rendered, so place the routes here
    <Route path=... component=() => <ComponentInsideDashboard />
</Dashboard>

您应该已经在仪表板中呈现实际内容(动态内容,而不是静态Dashboard)。由于每条路由都返回包裹在Dashboard 中的动态组件,因此Dashboard 将被多次渲染。

更简单地说:由于您希望Dashboard 只呈现一次,因此您应该只在一个地方使用它。

不同布局的正确方式

如果您还想在没有布局 (Dashboard) 或多个不同布局的情况下呈现内容,您可以简单地使用嵌套路由。

export const BaseApplicationRoutes = () => 
    return (
        <BrowserRouter>
            <Switch>
                <Route path="/dashboard1" component=<Dashboard1 />/>
                <Route path="/dashboard2" component=<Dashboard2 />/>
                <Route path="/noDashboard" component=<NoDashboard />/>
            </Switch>
        </BrowserRouter>
    )

<Dashboard1> // Dashboard2 could also look like this
    <Dashboard1Menu>
        <SideNav /> // e.g. containing links with history.push()
    </Dashboard1Menu>

    // Routes containing dynamic content
    <Route path=... component=() => <ComponentWithDashboard1 />
</Dashboard1>
<NoDashboard>
    // any content or even more routes rendering content without a layout
</NoDashboard>

【讨论】:

这是一个不错的方法!如果您想更新例如,您可能还会发现这篇博文很有用。 SideNav 来自您的一条路线:gregberge.com/blog/react-scalable-layout

以上是关于使用 react-router-dom 停止页面中侧边栏的重新渲染的主要内容,如果未能解决你的问题,请参考以下文章

页面未呈现;在 react-router-dom 中使用受保护的路由将道具传递给孩子时

使用 react-router-dom 重新加载页面时出现问题

为啥如果我使用 React-Router-Dom 刷新页面我无法获得

React:react-router-dom Redirect 不是重新加载页面,而是更改 URL

React-Router-Dom:让主页成为登陆页面

React-router-dom :是不是可以使用 Link 而不将用户路由到另一个页面?