refactor: prevent rendering multiple times on search

This commit is contained in:
EnixCoda 2020-10-26 22:27:21 +08:00
parent 3203f9426e
commit b0bcb7130c
No known key found for this signature in database
GPG key ID: 0C1A07377913A1DD
4 changed files with 71 additions and 38 deletions

View file

@ -42,9 +42,30 @@ const RawFileExplorer: React.FC<Props & ConnectorState> = function RawFileExplor
if (visibleNodes?.focusedNode) focusFileExplorer()
})
const renderActions: ((node: TreeNode) => React.ReactNode) | undefined = React.useMemo(
() =>
visibleNodes?.lastMatch?.match.searchKey
? node => (
<button
title={'Reveal in file tree'}
className={'go-to-button'}
onClick={e => {
e.stopPropagation()
e.preventDefault()
goTo(node.path.split('/'))
}}
>
<Icon type="go-to" />
</button>
)
: undefined,
[visibleNodes, goTo],
)
function renderFiles(visibleNodes: VisibleNodes) {
const inSearch = searchKey !== ''
const { nodes } = visibleNodes
const searchKey = visibleNodes.lastMatch?.match.searchKey
const inSearch = searchKey !== ''
if (inSearch && nodes.length === 0) {
return (
<Text marginTop={6} textAlign="center" color="text.gray">
@ -58,25 +79,8 @@ const RawFileExplorer: React.FC<Props & ConnectorState> = function RawFileExplor
<ListView
height={height}
width={width}
searchKey={searchKey}
onNodeClick={onNodeClick}
renderActions={
searchKey
? node => (
<button
title={'Reveal in file tree'}
className={'go-to-button'}
onClick={e => {
e.stopPropagation()
e.preventDefault()
goTo(node.path.split('/'))
}}
>
<Icon type="go-to" />
</button>
)
: undefined
}
renderActions={renderActions}
visibleNodes={visibleNodes}
expandTo={expandTo}
metaData={metaData}
@ -132,11 +136,19 @@ const VirtualNode = React.memo(function VirtualNode({
style,
data,
}: ListChildComponentProps) {
const { regex, onNodeClick, renderActions, visibleNodes } = data
const { onNodeClick, renderActions, visibleNodes } = data
if (!visibleNodes) return null
const { nodes, focusedNode, expandedNodes, loading, depths } = visibleNodes as VisibleNodes
const {
lastMatch,
nodes,
focusedNode,
expandedNodes,
loading,
depths,
} = visibleNodes as VisibleNodes
const node = nodes[index]
const searchKey = lastMatch?.match.searchKey
return (
<Node
style={style}
@ -148,7 +160,7 @@ const VirtualNode = React.memo(function VirtualNode({
expanded={expandedNodes.has(node.path)}
onClick={onNodeClick}
renderActions={renderActions}
regex={regex}
regex={searchKey && isValidRegexpSource(searchKey) ? new RegExp(searchKey, 'gi') : undefined}
/>
)
})
@ -156,7 +168,6 @@ const VirtualNode = React.memo(function VirtualNode({
type ListViewProps = {
height: number
width: number
searchKey: string
onNodeClick(event: React.MouseEvent<HTMLElement, MouseEvent>, node: TreeNode): void
renderActions?(node: TreeNode): React.ReactNode
visibleNodes: VisibleNodes
@ -167,7 +178,6 @@ function ListView({
height,
metaData,
expandTo,
searchKey,
onNodeClick,
renderActions,
visibleNodes,
@ -193,12 +203,11 @@ function ListView({
const itemData = React.useMemo(
() => ({
regex: searchKey && isValidRegexpSource(searchKey) ? new RegExp(searchKey, 'gi') : undefined,
onNodeClick,
renderActions,
visibleNodes,
}),
[searchKey, onNodeClick, renderActions, visibleNodes],
[onNodeClick, renderActions, visibleNodes],
)
return (

View file

@ -137,7 +137,12 @@ type Props = {
onClick?: (event: React.MouseEvent<HTMLElement>) => void
} & IconProps
export function Icon({ type, className = undefined, placeholder, ...otherProps }: Props) {
export const Icon = React.memo(function Icon({
type,
className = undefined,
placeholder,
...otherProps
}: Props) {
let children: React.ReactNode = null
if (!placeholder) {
const { name, IconComponent } = getSVGIconComponent(type)
@ -148,4 +153,4 @@ export function Icon({ type, className = undefined, placeholder, ...otherProps }
{children}
</div>
)
}
})

View file

@ -2,7 +2,6 @@ import { GetCreatedMethod, MethodCreator } from 'driver/connect'
import { platform } from 'platforms'
import { Config } from 'utils/configHelper'
import * as DOMHelper from 'utils/DOMHelper'
import { searchKeyToRegexp } from 'utils/general'
import { VisibleNodes, VisibleNodesGenerator } from 'utils/VisibleNodesGenerator'
export type Props = {
@ -182,8 +181,7 @@ export const onFocusSearchBar: BoundMethodCreator = dispatch => () => dispatch.c
export const search: BoundMethodCreator<[string]> = dispatch => searchKey => {
dispatch.set({ searchKey, searched: searchKey !== '' })
const regexp = searchKeyToRegexp(searchKey)
visibleNodesGenerator.search(regexp && (node => regexp.test(node.name)))
visibleNodesGenerator.search({ searchKey })
}
export const goTo: BoundMethodCreator<[string[]]> = dispatch => currentPath => {

View file

@ -1,5 +1,5 @@
import { EventHub } from './EventHub'
import { findNode, traverse, withEffect } from './general'
import { findNode, searchKeyToRegexp, traverse, withEffect } from './general'
function search(
root: TreeNode,
@ -131,12 +131,27 @@ class ShakeLayer extends BaseLayer {
}
shake = withEffect(
(p?: { match: (node: TreeNode) => boolean; onChildMatch: (node: TreeNode) => void }) => {
(p?: {
match: {
// shape in object for better extensibility
searchKey: string
}
onChildMatch: (node: TreeNode) => void
}) => {
this.lastMatch = p
if (p) {
const { match, onChildMatch } = p
this.shackedRoot = search(this.baseRoot, match, onChildMatch)
} else this.shackedRoot = this.baseRoot
const {
match: { searchKey },
onChildMatch,
} = p
const regexp = searchKeyToRegexp(searchKey)
if (regexp) {
this.shackedRoot = search(this.baseRoot, node => regexp.test(node.name), onChildMatch)
return
}
}
this.shackedRoot = this.baseRoot
},
() => this.shakeHub.emit('emit', this.shackedRoot),
)
@ -232,7 +247,7 @@ class FlattenLayer extends CompressLayer {
focusNode = (node: TreeNode | null) => {
if (this.focusedNode !== node) {
this.focusedNode = node
this.focusedNode = node
this.flattenHub.emit('emit', null)
}
}
@ -284,7 +299,11 @@ class FlattenLayer extends CompressLayer {
}
}, this.generateVisibleNodes)
search = (match: ((node: TreeNode) => boolean) | null) => {
search = (
match: {
searchKey: string
} | null,
) => {
// this.focusNode(null)
this.shake(
match
@ -305,6 +324,7 @@ type Options = {
export type VisibleNodes = {
loading: BaseLayer['loading']
lastMatch: ShakeLayer['lastMatch']
depths: CompressLayer['depths']
nodes: FlattenLayer['nodes']
expandedNodes: FlattenLayer['expandedNodes']
@ -333,6 +353,7 @@ export class VisibleNodesGenerator extends FlattenLayer {
get visibleNodes(): VisibleNodes {
return {
nodes: this.nodes,
lastMatch: this.lastMatch,
depths: this.depths,
expandedNodes: this.expandedNodes,
focusedNode: this.focusedNode,