2016-08-01 3 views
6

Я использую redux с реакцией и машинописным текстом для моего приложения. Я работаю со многими элементами, используемыми в разных местах моего приложения. Мое состояние выглядит следующим образом:Избегайте повторного рендеринга большого списка элементов с помощью реакции-сокращения

{ 
    items: {42: {}, 53: {}, ... }, //A large dictionary of items 
    itemPage1: { 
     itemsId: [ 42, 34, 4 ], 
     ... 
    }, 
    itemPage2: { ... 
    }, 
    ... 
} 

Пользователь может изменить некоторые атрибуты items диспетчерские некоторые действия. Когда это произойдет, мне нужно перерисовать компоненты, которые были изменены на каждой странице. Проблема в том, что мои вещи довольно большие, и я не могу позволить себе перерисовать их все при каждой небольшой модификации. Мне было интересно, как этот подход будет работать:

  • У меня есть компонент <ItemPage1> кулака, который подключается к магазину, чтобы получить все из состояний, хранящихся в дереве под itemPage1 например, список предметов id: itemsId.
  • Внутри <ItemPage1> я петля над itemsId собственности для создания нескольких FilterItem компонентов: itemsId.map(itemId => return <FilterItem id=itemId>);
  • Наконец каждый Item подключен с помощью ownProps, чтобы получить правильную часть государства:

    const mapStateToItemProps = (state, ownProps) => { 
        return { 
         item: state.items[ownProps.id], 
        } 
    } 
    const mapDispatchToItemProps = (dispatch, ownProps) => { 
        return null; 
    } 
    const FilterItem = connect(
        mapStateToItemProps, 
        mapDispatchToItemProps 
    )(Item) 
    

Может вы подтверждаете или опровергаете, что если я обновляю элемент id 42, то только этот элемент будет повторно отображен?

+1

Возможно, это для вас http://stackoverflow.com/questions/38493521/whats-the-best-way-to-deal-with-a-normalized-response/38499471#38499471 –

+0

Ваш комментарий стал актуальным, но вопрос состоял в том, что все элементы были переделаны или нет. – user3091275

ответ

6

При рендеринге большой список, вы должны принять во внимание соображения несколько вещей:

  • Lower общее количество элементов DOM, которые вам нужно сделать (на не оказывающего элементы, которые на самом деле не видны на экране, а также виртуализация)
  • не пересборка элементов, которые не изменилось

в принципе, то, что вы хотите, чтобы избежать является полной повторной визуализацией вашего списка (или страницы), когда пользователь редактирует один один ряд. Это может быть достигнуто именно так, как вы это сделали, т. Е. Путем перехода к контейнеру списка только идентификаторов предметов, которые необходимо отобразить, и сопоставить эти идентификаторы с connect каждым компонентом с помощью ownProps. Если у вас есть свалка <Item/>, то ваш компонент <ItemPage/> создаст подключенный компонент connect(<Item/>).

Это будет работать, если вы положили console.log('item rendered') в свой класс компонентов <Item/>, вы заметите, что есть только один звонок.

НО (и это большой, но), что не является очевидным при работе с react-redux является то, что все подключенные компоненты, которые зависят от их ownProps будет всегда если повторно вызывать какой-либо части изменения состояния. В вашем случае, даже если компоненты <Item/> не будут повторно отображены, их завернутый компонент connect(Item) будет! Если у вас несколько десятков элементов, вы можете столкнуться с некоторой задержкой, если действия нужно быстро отправить (например, при вводе ввода). Как этого избежать? Используйте функцию заводской использовать ownProps в качестве исходного реквизита:

const mapStateToItemProps = (_, initialProps) => (state) => { 
    return { 
     item: state.items[initialProps.id], // we're not relying on the second parameters "ownProps" here, so the wrapper component will not rerender 
    } 
} 
const mapDispatchToItemProps = (dispatch, ownProps) => { 
    return null; 
} 
const FilterItem = connect(
    mapStateToItemProps, 
    mapDispatchToItemProps 
)(Item) 

Я предлагаю вам взглянуть на this other answer.

Вы также можете быть заинтересованы в этих прекрасных горках: Big List High Performance React & Redux

И, наконец, вы должны окончательно взглянуть на react-virtualized выполнять виртуализацию вашего списка (т.е. отображается только элемент, который пользователь может реально увидеть).

0

Хорошо, я нашел это обсуждение: https://github.com/reactjs/redux/issues/1303

На дне это ясно сказано (от нескольких главных героев):

[...] реагировать-перевождь заботится об этом. Он позволяет указать конкретные части состояния, о которых вы заботитесь, и берет на себя обязательство избавиться от обновления компонентов React, когда соответствующие части не изменились.

[...] Просто хотел, чтобы полностью понять, что происходит под капотом здесь, Так что, если магазин Redux обновляется, но состояние один конкретный компонент не изменился, Redux не вызовет forceUpdate () для этого компонента? [...]

Обертка компонент генерируется функцией подключения React-Redux (в) делает несколько проверок, чтобы попытаться свести к минимуму количество раз, ваш фактический компонент должен повторно вынести. Это включает стандартную реализацию shouldComponentUpdate и выполнение неглубоких проверок равенства в реквизитах, входящих в ваш компонент (включая то, что возвращается с mapStateToProps). Так что да, как правило, связанный компонент будет только повторно отображать, когда значения, которые он извлекает из состояния, изменились.

Поэтому я считаю, что моя реализация хороша, она не будет повторно отображать все элементы, поскольку только один элемент увидит, что его свойства изменены.

+1

Вы почти на 100% правы, есть только один доступ с использованием 'ownProps', который делает все ваши компоненты-обертки повторно рендерингом каждый раз. Взгляните на мой ответ! – Pcriulan

Смежные вопросы