Memoize FileTree and outline toggle button components (#16776)

GitOrigin-RevId: 299ed9d568650ce37edba87643112d1cd6d12fd4
This commit is contained in:
Alf Eaton 2024-02-01 09:41:12 +00:00 committed by Copybot
parent f06f2ef99e
commit c443322a41
8 changed files with 93 additions and 58 deletions

View file

@ -176,7 +176,10 @@ export const ChatContext = createContext<
>(undefined)
export const ChatProvider: FC = ({ children }) => {
const clientId = useRef(uuid())
const clientId = useRef<string>()
if (clientId.current === undefined) {
clientId.current = uuid()
}
const user = useUserContext()
const { _id: projectId } = useProjectContext()

View file

@ -1,4 +1,4 @@
import React, { useCallback, useState } from 'react'
import React, { memo, useCallback, useState } from 'react'
import { useUserContext } from '@/shared/context/user-context'
import { useReferencesContext } from '@/features/ide-react/context/references-context'
import { useIdeReactContext } from '@/features/ide-react/context/ide-react-context'
@ -7,7 +7,7 @@ import { RefProviders } from '../../../../../types/user'
import FileTreeRoot from '@/features/file-tree/components/file-tree-root'
import { useFileTreeOpenContext } from '@/features/ide-react/context/file-tree-open-context'
export function FileTree() {
export const FileTree = memo(function FileTree() {
const user = useUserContext()
const { indexAllReferences } = useReferencesContext()
const { setStartedFreeTrial } = useIdeReactContext()
@ -44,4 +44,4 @@ export function FileTree() {
/>
</div>
)
}
})

View file

@ -0,0 +1,24 @@
import { memo, type Dispatch, type SetStateAction } from 'react'
import Icon from '@/shared/components/icon'
import { useTranslation } from 'react-i18next'
export const OutlineItemToggleButton = memo<{
expanded: boolean
setExpanded: Dispatch<SetStateAction<boolean>>
}>(({ expanded, setExpanded }) => {
const { t } = useTranslation()
return (
<button
className="outline-item-expand-collapse-btn"
onClick={() => setExpanded(value => !value)}
aria-label={expanded ? t('collapse') : t('expand')}
>
<Icon
type={expanded ? 'angle-down' : 'angle-right'}
className="outline-caret-icon"
/>
</button>
)
})
OutlineItemToggleButton.displayName = 'OutlineItemToggleButton'

View file

@ -2,9 +2,8 @@ import { useState, useEffect, useRef, memo } from 'react'
import PropTypes from 'prop-types'
import scrollIntoViewIfNeeded from 'scroll-into-view-if-needed'
import classNames from 'classnames'
import { useTranslation } from 'react-i18next'
import OutlineList from './outline-list'
import Icon from '../../../shared/components/icon'
import { OutlineItemToggleButton } from '@/features/outline/components/outline-item-toggle-button'
const OutlineItem = memo(function OutlineItem({
outlineItem,
@ -13,8 +12,6 @@ const OutlineItem = memo(function OutlineItem({
matchesHighlightedLine,
containsHighlightedLine,
}) {
const { t } = useTranslation()
const [expanded, setExpanded] = useState(true)
const titleElementRef = useRef()
const isHighlightedRef = useRef(false)
@ -30,10 +27,6 @@ const OutlineItem = memo(function OutlineItem({
'outline-item-link-highlight': isHighlighted,
})
function handleExpandCollapseClick() {
setExpanded(!expanded)
}
function handleOutlineItemLinkClick(event) {
const syncToPdf = event.detail === 2 // double-click = sync to PDF
jumpToLine(outlineItem.line, syncToPdf)
@ -65,18 +58,12 @@ const OutlineItem = memo(function OutlineItem({
aria-label={outlineItem.title}
>
<div className="outline-item-row">
{outlineItem.children ? (
<button
className="outline-item-expand-collapse-btn"
onClick={handleExpandCollapseClick}
aria-label={expanded ? t('collapse') : t('expand')}
>
<Icon
type={expanded ? 'angle-down' : 'angle-right'}
className="outline-caret-icon"
{!!outlineItem.children && (
<OutlineItemToggleButton
expanded={expanded}
setExpanded={setExpanded}
/>
</button>
) : null}
)}
<button
className={itemLinkClasses}
onClick={handleOutlineItemLinkClick}

View file

@ -1,11 +1,9 @@
import React, { useEffect } from 'react'
import classNames from 'classnames'
import { useTranslation } from 'react-i18next'
import OutlineRoot from './outline-root'
import Icon from '../../../shared/components/icon'
import withErrorBoundary from '../../../infrastructure/error-boundary'
import Tooltip from '../../../shared/components/tooltip'
import { OutlineToggleButton } from '@/features/outline/components/outline-toggle-button'
const OutlinePane = React.memo<{
isTexFile: boolean
@ -28,8 +26,6 @@ const OutlinePane = React.memo<{
expanded,
toggleExpanded,
}) {
const { t } = useTranslation()
const isOpen = Boolean(isTexFile && expanded)
useEffect(() => {
@ -43,32 +39,13 @@ const OutlinePane = React.memo<{
return (
<div className={headerClasses}>
<header className="outline-header">
<button
className="outline-header-expand-collapse-btn"
disabled={!isTexFile}
onClick={toggleExpanded}
aria-label={expanded ? t('hide_outline') : t('show_outline')}
>
<Icon
type={isOpen ? 'angle-down' : 'angle-right'}
className="outline-caret-icon"
<OutlineToggleButton
toggleExpanded={toggleExpanded}
expanded={expanded}
isOpen={isOpen}
isPartial={isPartial}
isTexFile={isTexFile}
/>
<h4 className="outline-header-name">{t('file_outline')}</h4>
{isPartial && (
<Tooltip
id="partial-outline"
description={t('partial_outline_warning')}
overlayProps={{ placement: 'top' }}
>
<span role="status">
<Icon
type="exclamation-triangle"
aria-label={t('partial_outline_warning')}
/>
</span>
</Tooltip>
)}
</button>
</header>
{isOpen && (
<div className="outline-body">

View file

@ -0,0 +1,44 @@
import Icon from '@/shared/components/icon'
import Tooltip from '@/shared/components/tooltip'
import React, { memo } from 'react'
import { useTranslation } from 'react-i18next'
export const OutlineToggleButton = memo<{
isTexFile: boolean
toggleExpanded: () => void
expanded?: boolean
isOpen: boolean
isPartial: boolean
}>(({ isTexFile, toggleExpanded, expanded, isOpen, isPartial }) => {
const { t } = useTranslation()
return (
<button
className="outline-header-expand-collapse-btn"
disabled={!isTexFile}
onClick={toggleExpanded}
aria-label={expanded ? t('hide_outline') : t('show_outline')}
>
<Icon
type={isOpen ? 'angle-down' : 'angle-right'}
className="outline-caret-icon"
/>
<h4 className="outline-header-name">{t('file_outline')}</h4>
{isPartial && (
<Tooltip
id="partial-outline"
description={t('partial_outline_warning')}
overlayProps={{ placement: 'top' }}
>
<span role="status">
<Icon
type="exclamation-triangle"
aria-label={t('partial_outline_warning')}
/>
</span>
</Tooltip>
)}
</button>
)
})
OutlineToggleButton.displayName = 'OutlineToggleButton'

View file

@ -1,11 +1,11 @@
import { createContext, FC, useContext } from 'react'
import { createContext, FC, useContext, useMemo } from 'react'
import getMeta from '../../utils/meta'
import { User } from '../../../../types/user'
export const UserContext = createContext<User | undefined>(undefined)
export const UserProvider: FC = ({ children }) => {
const user = getMeta('ol-user')
const user = useMemo(() => getMeta('ol-user'), [])
return <UserContext.Provider value={user}>{children}</UserContext.Provider>
}

View file

@ -43,7 +43,7 @@ function setTitle(title: string) {
}
function useBrowserWindow() {
const [hasFocus, setHasFocus] = useState(document.hasFocus())
const [hasFocus, setHasFocus] = useState(() => document.hasFocus())
useEffect(() => {
function handleFocusEvent() {