Запоминание функционального компонента с использованием response-redux, reselect и React.memo () - PullRequest
0 голосов
/ 24 апреля 2020

Я создал приложение на ReactJS 16.8.5 и React-Redux 3.7.2. Когда приложение загружает приложения, устанавливается начальное хранилище, и подписки базы данных настраиваются для базы данных Firebase Realtime. Приложение содержит заголовок, Sidebar и раздел содержимого.
Я реализовал повторный выбор вместе с React.memo , чтобы избежать повторного рендеринга при смене реквизита, но компонента Sidebar все еще перерисовывает. Используя React Profiler API и функцию сравнения areEqual в React.memo, я вижу, что Sidebar отрисовывается несколько раз, хотя реквизиты равны.

app.js

//Imports etc...
const jsx = (
  <React.StrictMode>
    <Provider store={store}>
      <AppRouter />
    </Provider>
  </React.StrictMode>
)

let hasRendered = false
const renderApp = () => {
  if (!hasRendered) { //make sure app only renders one time
    ReactDOM.render(jsx, document.getElementById('app'))
    hasRendered = true
  }
}

firebase.auth().onAuthStateChanged((user) => {
  if (user) {
    // Set initial store and db subscriptions
    renderApp()
  }
})

AppRouter.js

//Imports etc...
const AppRouter = ({}) => {
  //...
  return (
    <React.Fragment>
      //uses Router instead of BrowserRouter to use our own history and not the built in one
      <Router history={history}>    
        <div className="myApp">
          <Route path="">
            <Sidebar ...props />
          </Route>
          //More routes here...
        </div>
      </Router>
    </React.Fragment>
  )
}
//...
export default connect(mapStateToProps, mapDispatchToProps)(AppRouter)

Sidebar.js

//Imports etc...
export const Sidebar = (props) => {
  const onRender = (id, phase, actualDuration, baseDuration, startTime, commitTime) => {
    if (id !== 'Sidebar') { return }
    console.log('onRender', phase, actualDuration)
  }
  return (
    <Profiler id="Sidebar" onRender={onRender}>
      <React.Fragment>
        {/* Contents of Sidebar */}
      </React.Fragment>
    </Profiler>
}

const getLang = state => (state.usersettings) ? state.usersettings.language : 'en'
const getMediaSize = state => (state.route) ? state.route.mediaSize : 'large'
const getNavigation = state => state.navigation
const getMyLang = createSelector(
  [getLang], (lang) => console.log('Sidebar lang val changed') || lang
)
const getMyMediaSize = createSelector(
  [getMediaSize], (mediaSize) => console.log('Sidebar mediaSize val changed') || mediaSize
)
const getMyNavigation = createSelector(
  [getNavigation], (navigation) => console.log('Sidebar navigation val changed') || navigation
)
const mapStateToPropsMemoized = (state) => {
  return {
    lang: getMyLang(state),
    mediaSize: getMyMediaSize(state),
    navigation: getMyNavigation(state)
  }
}

const areEqual = (prevProps, nextProps) => {
  const areStatesEqual = _.isEqual(prevProps, nextProps)
  console.log('Sidebar areStatesEqual', areStatesEqual)
  return areStatesEqual
}
export default React.memo(connect(mapStateToPropsMemoized, mapDispatchToProps)(Sidebar),areEqual)

Первоначальный рендеринг выглядит нормально вплоть до Sidebar navigation val changed - после этого компонент повторно рендерит весь много раз - почему!?

Console output - initial render

onRender Sidebar mount 572 
Sidebar mediaSize val changed 
Profile Sidebar areEqual true 
Sidebar navigation val changed 
onRender Sidebar update 153 
Sidebar navigation val changed 
onRender Sidebar update 142 
onRender Sidebar update 103 
onRender Sidebar update 49 
onRender Sidebar update 5 
onRender Sidebar update 2 
onRender Sidebar update 12 
onRender Sidebar update 3 
onRender Sidebar update 2 
onRender Sidebar update 58 
onRender Sidebar update 2 
onRender Sidebar update 4 
onRender Sidebar update 5 
onRender Sidebar update 4

Последующий рендеринг не влияет ни на какую часть магазина, которая сопоставлена ​​с реквизитами (местоположение), но компонент все еще рендеринг.

Console output - subsequent render

Profile Sidebar areEqual true
onRender Sidebar update 76
onRender Sidebar update 4

Я ожидаю, что Sidebar будет запомнен и рендерится / рендерится только несколько раз во время монтирования / обновления хранилища во время начальной загрузки.

Почему компонент Sidebar отображается так много раз?

С уважением / K

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...