React Redux 和 should 组件更新优化

nl *_*pkr 3 reactjs redux react-redux

代码:

根组件

    <Provider store={Store}>
       <AppLayoutContainer>
           {this.props.template}
       </AppLayoutContainer>
    </Provider>
Run Code Online (Sandbox Code Playgroud)

应用布局容器

....some code

  return(
    <div className={`AppLayoutContainer`}>
       <Modal isOpen={isModalShown} .... />
       <div>{children}</div>
     </div>
  )

....some code

function mapStateToProps(state) {
  const { app } = state;
  return {
    isModalShown: app.isModalShown
   }
}

export default connect(mapStateToProps)(AppLayoutContainer);
Run Code Online (Sandbox Code Playgroud)

问题:

每次isModalShown从 Redux获取 Applayoutcontainer 时,我的整个应用程序都在重新渲染,而且非常糟糕。我所需要的只是重新渲染 Modal 组件,不要触摸我的children. 我认为使用ShouldComponentUpdate方法是可能的,但我真的不明白该怎么做。

有任何想法吗 ?我知道有人在他的项目中做到了这一点,并且可以为此提供一些最佳实践建议。谢谢


更新:

阅读所有答案,是的,将 Modal 与 Store 连接是一个很好的解决方案,但是如果

1)我希望模态组件像或组件一样纯(可重用)?

2)我需要isModalShown在 AppLayoutContainer 中使用?

return(
    <div className={`AppLayoutContainer`}>
       <Modal isOpen={isModalShown} .... />
       <div>{children}</div>
     </div>
  )
Run Code Online (Sandbox Code Playgroud)

更新 2.0

谢谢你的回答,但我能用这个做什么

主要问题是我在显示Modal组件时需要模糊所有内容,因为我知道blur()只能应用于要工作的内容(而不是覆盖我的内容的绝对位置 div),并且这样做

return(
        <div className={`AppLayoutContainer`}>
           <Modal isOpen={isModalShown} .... />
           <div className={isModalShown ? 'blured' : null }>{children}</div>
         </div>
      )
Run Code Online (Sandbox Code Playgroud)

但是我的整个应用程序每次出现时都会重新渲染Modal,我需要冻结它。在这里构建容器child并执行的解决方案shouldcomponentupdate不好,React 如何比较整个组件?它只比较 props 中的非不可变字段。

任何解决方案?

DDS*_*DDS 5

你应该做的是没有通过isModalAppLayoutContainermapStateToProps功能,而是connectModal自身。

mapStateToProps该更改的任何结果都将导致connected 组件重新渲染。在您的情况下,您的mapStateToProps connectedAppLayoutContainer返回isModalShown导致您AppLayoutContainer重新渲染的值。

如果您只想重新渲染Modal本身,那么只需

export default connect(state => ({isOpen: state.app.isModalShown}))(Modal)
Run Code Online (Sandbox Code Playgroud)

在您的Modal文件中,或者如果您更喜欢在单独的文件中。

还要isModalShown从 中删除道具,AppLayoutContainer因为您不需要它,并且因为将它留在那里意味着AppLayoutContainer每次isModalShown更改时仍会重新渲染(这是您要修复的)。

更新有关问题的更新:

问题 1:

你可以拥有纯 Modal

export default function Modal(props) {
  return <span>Open={props.isOpen}</span>;
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以为特定用途制作特定的 Modal:

import Modal from './modal';
import { connect } from 'react-redux';

export default const AppLayoutModal = connect(state => ({isOpen: state.app.isModalShown}))(Modal);
Run Code Online (Sandbox Code Playgroud)

对于各种单独的模态,您可以多次执行此操作。事实上,这就是为什么使用纯组件是个好主意的原因。

问题 2:

如果你想使用isModalShowninAppLayoutContainer那么你有一些选择:

  • 就用它。React 总是渲染整个组件。因为它只是一种渲染方法。它会更新 DOM(如果有的话),更细粒度,但是如果您希望在发生变化时渲染更少的东西,那么您可以让渲染函数变小。如果你让组件变大,那么整个东西都会重新渲染。
  • 您可以将组件切成更小的组件,以便它们可以单独呈现。您可以制作一个小组件,仅直接使用isModalShownvia connect,因此大组件AppLayoutContainer不会改变。子组件可以并且确实独立于其父组件进行更新。

更新 2

要模糊整个应用程序,只需向应用程序添加一个类。子组件不会重新渲染。Redux 会阻止孩子渲染,因为它注意到孩子没有使用isModalShown. 生成的 React 元素与之前的渲染完全相同(引用)。React 看到它是同一个元素并且知道不更新整个树。这是有效的,因为 React 元素是不可变的。您的整个应用程序将不会重新渲染。实际上,React只会从 class 属性中添加或删除类。

如果您的孩子不使用 Redux 来防止渲染沿着树走,那么您可以将孩子包装在 Redux 连接的组件中。或者,您可以使用shouldComponentUpdate来阻止渲染子项。

Bare React 要求您从根向树下发送数据。Redux 要求您在需要的地方将数据注入到树中。后者的好处是不需要重新渲染其他任何东西。如果没有 Redux,除非组件用于停止传播,否则每次更改时都会重新渲染整个树shouldComponentUpdate。但是,这不仅会停止当前组件的渲染,还会停止所有子组件的渲染。Redux 消除了这一点,因为子组件可以在没有父组件合作或不知情的情况下更新它们的 props。

简而言之:到处使用 Redux 以提高速度。