Ответ 1
I просто добавил новый пример, показывающий именно это.
Вы можете запустить его следующим образом:
git clone https://github.com/rackt/redux.git
cd redux/examples/tree-view
npm install
npm start
open http://localhost:3000/
Я новичок в React, Redux и ImmutableJS и столкнулся с некоторыми проблемами производительности.
У меня есть большая древовидная структура данных, которую я сейчас храню в виде плоского списка в этой структуре:
new Map({
1: new Node({
id: 1,
text: 'Root',
children: [2,3]
}),
2: new Node({
id: 2,
text: 'Child 1',
children: [4]
}),
3: new Node({
id: 3,
text: 'Child 2',
children: []
}),
4: new Node({
id: 4,
text: 'Child of child 1',
children: []
})
});
При структурировании его как плоского списка упрощается обновление узлов, я обнаруживаю, что взаимодействие становится вялым по мере роста дерева. Взаимодействие включает в себя возможность выбора одного или нескольких узлов, переключения видимости их дочерних узлов, обновления текста и т.д. Похоже, что ключевой причиной вялого интерфейса является то, что все дерево перерисовывается для каждого взаимодействия.
Я хочу использовать shouldComponentUpdate
, чтобы при обновлении node 3 узлы 2 и 4 не обновлялись. Это было бы легко, если бы данные были сохранены как дерево (я мог бы просто проверить, есть ли this.props !== nextProps
), но поскольку данные хранятся в плоском списке, проверка будет значительно сложнее.
Как мне хранить данные и использовать shouldComponentUpdate
(или другие методы) для поддержки гладкого интерфейса с сотнями или тысячами узлов дерева?
Edit
Я подключил хранилище на верхнем уровне, а затем должен передать весь хранилище до подкомпонентов.
Моя структура:
<NodeTree>
<NodeBranch>
<Node>{{text}}</Node>
<NodeTree>...</NodeTree>
</NodeBranch>
<NodeBranch>
<Node>{{text}}</Node>
<NodeTree>...</NodeTree>
</NodeBranch>
...
</NodeTree>
<Node>
может выполнить простую проверку с помощью shouldComponentUpdate
, чтобы узнать, изменился ли заголовок, но у меня нет аналогичного решения для использования в <NodeTree>
или <NodeBranch>
, учитывая рекурсивный характер дерева.
Похоже, что лучшим решением (спасибо @Dan Abramov) было бы подключение каждого <NodeBranch>
, а просто подключение на верхнем уровне. Я проведу это сегодня вечером.
I просто добавил новый пример, показывающий именно это.
Вы можете запустить его следующим образом:
git clone https://github.com/rackt/redux.git
cd redux/examples/tree-view
npm install
npm start
open http://localhost:3000/
Решение Дэн Абрамова в 99% случаев обычно прекращается.
Но время вычисления, требуемое для каждого приращения, пропорционально O (n) количеству узлов в дереве, поскольку каждый подключенный node HOC должен выполнить немного кода (например, сопоставление идентичности...). Однако этот код довольно быстро выполняется.
Если вы протестируете решение Дэн Абрамов, с 10k узлами на моем ноутбуке, я начинаю видеть некоторую задержку при попытке увеличить счетчик (например, задержка в 100 мс). Вероятно, это намного хуже на дешевых мобильных устройствах.
Можно утверждать, что вы не должны пытаться отображать 10 000 элементов в DOM сразу, и я полностью согласен с этим, но если вы действительно хотите отображать множество элементов и подключать их, это не так просто.
Если вы хотите повернуть этот O (n) в O (1), вы можете реализовать свою собственную систему connect
, где HOC (компонент более высокого порядка ) подписка активируется только при обновлении базового счетчика вместо всех подписчиков HOC.
Я рассказал, как это сделать в этом .
Я создал issue для реакции-сокращения, чтобы connect
стал более гибким и позволял легко настраивать подписку на магазин через опции. Идея состоит в том, что вы должны иметь возможность повторно использовать код connect
и эффективно подписываться на изменения срезов штата вместо глобальных изменений состояния (т.е. store.subscribe()
).
const mapStateToProps = (state,props) => {node: selectNodeById(state,props.nodeId)}
const connectOptions = {
doSubscribe: (store,props) => store.subscribeNode(props.nodeId)
}
connect(mapStateToProps, undefined,connectOptions)(ComponentToConnect)
По-прежнему ваша собственная ответственность создать энхансер магазина с помощью метода subscribeNode
.