mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-07 20:31:06 -05:00
Merge pull request #10397 from overleaf/td-memoize-file-outline
Memoize file outline GitOrigin-RevId: cb086bab2b6ead251362180d776e7eaff18fc639
This commit is contained in:
parent
6ae22ff596
commit
81e2265e72
4 changed files with 57 additions and 21 deletions
|
@ -1,4 +1,4 @@
|
|||
import { useState, useEffect, useRef } from 'react'
|
||||
import { useState, useEffect, useRef, memo } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import scrollIntoViewIfNeeded from 'scroll-into-view-if-needed'
|
||||
import classNames from 'classnames'
|
||||
|
@ -6,15 +6,13 @@ import { useTranslation } from 'react-i18next'
|
|||
import OutlineList from './outline-list'
|
||||
import Icon from '../../../shared/components/icon'
|
||||
|
||||
function getChildrenLines(children) {
|
||||
return (children || [])
|
||||
.map(child => {
|
||||
return getChildrenLines(child.children).concat(child.line)
|
||||
})
|
||||
.flat()
|
||||
}
|
||||
|
||||
function OutlineItem({ outlineItem, jumpToLine, highlightedLine }) {
|
||||
const OutlineItem = memo(function OutlineItem({
|
||||
outlineItem,
|
||||
jumpToLine,
|
||||
highlightedLine,
|
||||
matchesHighlightedLine,
|
||||
containsHighlightedLine,
|
||||
}) {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const [expanded, setExpanded] = useState(true)
|
||||
|
@ -25,12 +23,8 @@ function OutlineItem({ outlineItem, jumpToLine, highlightedLine }) {
|
|||
'outline-item-no-children': !outlineItem.children,
|
||||
})
|
||||
|
||||
const hasHighlightedChild =
|
||||
!expanded &&
|
||||
getChildrenLines(outlineItem.children).includes(highlightedLine)
|
||||
|
||||
const isHighlighted =
|
||||
highlightedLine === outlineItem.line || hasHighlightedChild
|
||||
const hasHighlightedChild = !expanded && containsHighlightedLine
|
||||
const isHighlighted = matchesHighlightedLine || hasHighlightedChild
|
||||
|
||||
const itemLinkClasses = classNames('outline-item-link', {
|
||||
'outline-item-link-highlight': isHighlighted,
|
||||
|
@ -90,16 +84,21 @@ function OutlineItem({ outlineItem, jumpToLine, highlightedLine }) {
|
|||
</button>
|
||||
</div>
|
||||
{expanded && outlineItem.children ? (
|
||||
// highlightedLine is only provided to this list if the list contains
|
||||
// the highlighted line. This means that whenever the list does not
|
||||
// contain the highlighted line, the props provided to it are the same
|
||||
// and the component can be memoized.
|
||||
<OutlineList
|
||||
outline={outlineItem.children}
|
||||
jumpToLine={jumpToLine}
|
||||
isRoot={false}
|
||||
highlightedLine={highlightedLine}
|
||||
highlightedLine={containsHighlightedLine ? highlightedLine : null}
|
||||
containsHighlightedLine={containsHighlightedLine}
|
||||
/>
|
||||
) : null}
|
||||
</li>
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
OutlineItem.propTypes = {
|
||||
outlineItem: PropTypes.exact({
|
||||
|
@ -113,6 +112,8 @@ OutlineItem.propTypes = {
|
|||
}).isRequired,
|
||||
jumpToLine: PropTypes.func.isRequired,
|
||||
highlightedLine: PropTypes.number,
|
||||
matchesHighlightedLine: PropTypes.bool,
|
||||
containsHighlightedLine: PropTypes.bool,
|
||||
}
|
||||
|
||||
export default OutlineItem
|
||||
|
|
|
@ -1,32 +1,64 @@
|
|||
import PropTypes from 'prop-types'
|
||||
import classNames from 'classnames'
|
||||
import OutlineItem from './outline-item'
|
||||
import { memo } from 'react'
|
||||
|
||||
function OutlineList({ outline, jumpToLine, isRoot, highlightedLine }) {
|
||||
function getChildrenLines(children) {
|
||||
return (children || [])
|
||||
.map(child => {
|
||||
return getChildrenLines(child.children).concat(child.line)
|
||||
})
|
||||
.flat()
|
||||
}
|
||||
|
||||
const OutlineList = memo(function OutlineList({
|
||||
outline,
|
||||
jumpToLine,
|
||||
isRoot,
|
||||
highlightedLine,
|
||||
containsHighlightedLine,
|
||||
}) {
|
||||
const listClasses = classNames('outline-item-list', {
|
||||
'outline-item-list-root': isRoot,
|
||||
})
|
||||
return (
|
||||
<ul className={listClasses} role={isRoot ? 'tree' : 'group'}>
|
||||
{outline.map((outlineItem, idx) => {
|
||||
const matchesHighlightedLine =
|
||||
containsHighlightedLine && highlightedLine === outlineItem.line
|
||||
const itemContainsHighlightedLine =
|
||||
containsHighlightedLine &&
|
||||
getChildrenLines(outlineItem.children).includes(highlightedLine)
|
||||
|
||||
// highlightedLine is only provided to the item if the item matches or
|
||||
// contains the highlighted line. This means that whenever the item does
|
||||
// not contain the highlighted line, the props provided to it are the
|
||||
// same and the component can be memoized.
|
||||
return (
|
||||
<OutlineItem
|
||||
key={`${outlineItem.level}-${idx}`}
|
||||
outlineItem={outlineItem}
|
||||
jumpToLine={jumpToLine}
|
||||
highlightedLine={highlightedLine}
|
||||
highlightedLine={
|
||||
matchesHighlightedLine || itemContainsHighlightedLine
|
||||
? highlightedLine
|
||||
: null
|
||||
}
|
||||
matchesHighlightedLine={matchesHighlightedLine}
|
||||
containsHighlightedLine={itemContainsHighlightedLine}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
OutlineList.propTypes = {
|
||||
outline: PropTypes.array.isRequired,
|
||||
jumpToLine: PropTypes.func.isRequired,
|
||||
isRoot: PropTypes.bool,
|
||||
highlightedLine: PropTypes.number,
|
||||
containsHighlightedLine: PropTypes.bool,
|
||||
}
|
||||
|
||||
export default OutlineList
|
||||
|
|
|
@ -14,6 +14,7 @@ function OutlineRoot({ outline, jumpToLine, highlightedLine }) {
|
|||
jumpToLine={jumpToLine}
|
||||
isRoot
|
||||
highlightedLine={highlightedLine}
|
||||
containsHighlightedLine
|
||||
/>
|
||||
) : (
|
||||
<div className="outline-body-no-elements">
|
||||
|
|
|
@ -54,6 +54,7 @@ describe('<OutlineItem />', function () {
|
|||
outlineItem={outlineItem}
|
||||
jumpToLine={jumpToLine}
|
||||
highlightedLine={1}
|
||||
matchesHighlightedLine
|
||||
/>
|
||||
)
|
||||
|
||||
|
@ -71,6 +72,7 @@ describe('<OutlineItem />', function () {
|
|||
outlineItem={outlineItem}
|
||||
jumpToLine={jumpToLine}
|
||||
highlightedLine={2}
|
||||
containsHighlightedLine
|
||||
/>
|
||||
)
|
||||
|
||||
|
|
Loading…
Reference in a new issue