【问题标题】:How to optimize React/Redux chat perfomance?如何优化 React/Redux 聊天性能?
【发布时间】:2019-11-26 10:01:54
【问题描述】:

我有一个基于 React 和 Redux 的聊天。

聊天容器接收 messageIds 并使用 messageIds.map() 为每条消息呈现组件。该组件连接到 Redux,因此它接收 messageId 并仅在 messageId 更改时更新。

但在分析器中,我在收到新消息时看到了很多(React Tree Reconciliation: Completed Root)事件,大约需要 6 毫秒。如何防止这种和解或如何优化它?

例如,我在聊天中有 30 条消息,并且每条新消息的协调大约需要 6 毫秒 * 30 条消息 = 180 毫秒,即使消息组件没有重新呈现也是如此。下面我提供了 profiler 的截图。

Message received action

Zoomed reconciliation event

【问题讨论】:

  • 将消息组件包装在 React.memo 中,或者如果消息组件是一个类,则从 React.PureComponent 继承。我需要查看消息组件及其容器以提供更多有用的建议。
  • React 端组件的@HMR 已优化,我也在使用 shouldComponentUpdate 和 PureComponent,但是通过分析器,看起来 Redux 试图更新消息组件。在探查器中,我看到: 1. Connect(MessageItemContainer) [更新] 1.2。 Connect(MessageItemContainer).shouldComponentUpdate 1.3。 Connect(MessageItemContainer).componentWillUpdate 1.4。连接(消息项容器).getChildContext 1.5。 MessageItemContainer.shouldComponentUpdate
  • 如果你不是从 React.PureComponent 扩展而不是实现 shouldComponentUpdate 比我想看到 shouldComponentUpdate 和道具来自哪里以及你从父级传递的道具消息项。

标签: reactjs redux


【解决方案1】:

我使用 react-redux connect 和不必要的重新渲染创建了一个包含 3 个常见错误的示例:

  1. mapStateToProps 总是返回一个新对象(state=>({val:{new:reference}}) 你可以通过记忆结果来防止这种情况:()=>{const memoizedResult=createSelector(...);return state=>memoizedResult(state)

  2. 每次都传递一个新对象作为道具(称为坏道具)

  3. 每次都将新函数作为回调传递(称为错误回调属性)

const { Provider, connect } = ReactRedux;
const { createStore } = Redux;

const store = createStore(() =>
  //reducer always returns a new object
  ({
    val: 1,
  })
);
function App({ a }) {
  return (
    <div>
      <button onClick={a}>re render</button>
      <BadContainer message="bad container" />
      <GoodContainer
        message="bad prop"
        badProp={{ a: 22 }}
      />
      <GoodContainer
        message="bad callback prop"
        badCallback={() => 88}
      />
      <GoodContainer message="good container" />
    </div>
  );
}
function Message(props) {
  const rendered = React.useRef(0);
  rendered.current++;
  return (
    <div>
      {props.message} rendered: {rendered.current} times
    </div>
  );
}
const AppContainer = connect(() => ({ a: {} }), {
  a: () => ({ type: 'a' }),
})(App);
const BadContainer = connect(state =>
  //bad map state, always returns new object for props
  ({
    object: { newObject: state.val },
  })
)(Message);
const GoodContainer = connect(() => {
  //prepare memoized function that will only re create props
  //  if parameters to it changed (usually done with reselect)
  const memProps = ((lastVal, lastResult) => val => {
    if (lastVal !== val) {
      lastResult = {
        object: { newObject: val },
      };
      lastVal = val;
    }
    return lastResult;
  })();
  //return optimized map state to props using memoization
  return state => memProps(state.val);
}, {})(Message);
ReactDOM.render(
  <Provider store={store}>
    <AppContainer />
  </Provider>,
  document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.4/redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/7.1.1/react-redux.min.js"></script>
<div id="root"></div>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-08-04
    • 1970-01-01
    • 2019-04-20
    • 2018-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多