Skip to content

Commit 3158a69

Browse files
committed
refactor to fix perf warns
1 parent 22e9ccf commit 3158a69

2 files changed

Lines changed: 206 additions & 122 deletions

File tree

.oxlintrc.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"no-console": "error",
1212
"no-array-sort": "off",
1313
"rules-of-hooks": "error",
14+
"react/jsx-key": "error",
1415
"react-in-jsx-scope": "off",
1516
// @TODO these rules should be enabled, and the violations fixed
1617
"no-unsafe-type-assertion": "off"

src/react-portable-text.tsx

Lines changed: 205 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export function PortableText<B extends TypedObject = PortableTextBlock>({
6262
return <>{rendered}</>
6363
}
6464

65-
function getNodeRenderer (
65+
function getNodeRenderer(
6666
components: PortableTextReactComponents,
6767
handleMissingComponent: MissingComponentHandler,
6868
): NodeRenderer {
@@ -71,23 +71,59 @@ function getNodeRenderer (
7171
const key = node._key || `node-${index}`
7272

7373
if (isPortableTextToolkitList(node)) {
74-
return renderList(node, index, key)
74+
return (
75+
<RenderList
76+
key={key}
77+
renderNode={renderNode}
78+
components={components}
79+
handleMissingComponent={handleMissingComponent}
80+
node={node}
81+
index={index}
82+
/>
83+
)
7584
}
7685

7786
if (isPortableTextListItemBlock(node)) {
78-
return renderListItem(node, index, key)
87+
return (
88+
<RenderListItem
89+
key={key}
90+
renderNode={renderNode}
91+
components={components}
92+
handleMissingComponent={handleMissingComponent}
93+
node={node}
94+
index={index}
95+
/>
96+
)
7997
}
8098

8199
if (isPortableTextToolkitSpan(node)) {
82-
return renderSpan(node, index, key)
100+
return (
101+
<RenderSpan
102+
key={key}
103+
renderNode={renderNode}
104+
components={components}
105+
handleMissingComponent={handleMissingComponent}
106+
node={node}
107+
/>
108+
)
83109
}
84110

85111
if (hasCustomComponentForNode(node)) {
86112
return renderCustomBlock(node, index, key, isInline)
87113
}
88114

89115
if (isPortableTextBlock(node)) {
90-
return renderBlock(node, index, key, isInline)
116+
return (
117+
<RenderBlock
118+
key={key}
119+
renderNode={renderNode}
120+
components={components}
121+
handleMissingComponent={handleMissingComponent}
122+
node={node}
123+
index={index}
124+
isInline={isInline}
125+
/>
126+
)
91127
}
92128

93129
if (isPortableTextToolkitTextNode(node)) {
@@ -101,123 +137,6 @@ function getNodeRenderer (
101137
return node._type in components.types
102138
}
103139

104-
function renderListItem(node: PortableTextListItemBlock, index: number, key: string) {
105-
const tree = serializeBlock({node, index, isInline: false, renderNode})
106-
const renderer = components.listItem
107-
const handler = typeof renderer === 'function' ? renderer : renderer[node.listItem]
108-
const Li = handler || components.unknownListItem
109-
110-
if (Li === components.unknownListItem) {
111-
const style = node.listItem || 'bullet'
112-
handleMissingComponent(unknownListItemStyleWarning(style), {
113-
type: style,
114-
nodeType: 'listItemStyle',
115-
})
116-
}
117-
118-
let children = tree.children
119-
if (node.style && node.style !== 'normal') {
120-
// Wrap any other style in whatever the block serializer says to use
121-
const {listItem: _listItem, ...blockNode} = node
122-
children = renderNode({
123-
node: blockNode,
124-
index,
125-
isInline: false,
126-
renderNode,
127-
})
128-
}
129-
130-
return (
131-
<Li key={key} value={node} index={index} isInline={false} renderNode={renderNode}>
132-
{children}
133-
</Li>
134-
)
135-
}
136-
137-
function renderList(node: ReactPortableTextList, index: number, key: string) {
138-
const children = node.children.map((child, childIndex) =>
139-
renderNode({
140-
node: child._key ? child : {...child, _key: `li-${index}-${childIndex}`},
141-
index: childIndex,
142-
isInline: false,
143-
renderNode,
144-
}),
145-
)
146-
147-
const component = components.list
148-
const handler = typeof component === 'function' ? component : component[node.listItem]
149-
const List = handler || components.unknownList
150-
151-
if (List === components.unknownList) {
152-
const style = node.listItem || 'bullet'
153-
handleMissingComponent(unknownListStyleWarning(style), {
154-
nodeType: 'listStyle',
155-
type: style,
156-
})
157-
}
158-
159-
return (
160-
<List key={key} value={node} index={index} isInline={false} renderNode={renderNode}>
161-
{children}
162-
</List>
163-
)
164-
}
165-
166-
function renderSpan(node: ToolkitNestedPortableTextSpan, _index: number, key: string) {
167-
const {markDef, markType, markKey} = node
168-
const Span = components.marks[markType] || components.unknownMark
169-
const children = node.children.map((child, childIndex) =>
170-
renderNode({
171-
node: child,
172-
index: childIndex,
173-
isInline: true,
174-
renderNode,
175-
}),
176-
)
177-
178-
if (Span === components.unknownMark) {
179-
handleMissingComponent(unknownMarkWarning(markType), {
180-
nodeType: 'mark',
181-
type: markType,
182-
})
183-
}
184-
185-
return (
186-
<Span
187-
key={key}
188-
text={spanToPlainText(node)}
189-
value={markDef}
190-
markType={markType}
191-
markKey={markKey}
192-
renderNode={renderNode}
193-
>
194-
{children}
195-
</Span>
196-
)
197-
}
198-
199-
function renderBlock(node: PortableTextBlock, index: number, key: string, isInline: boolean) {
200-
const {_key, ...props} = serializeBlock({
201-
node,
202-
index,
203-
isInline,
204-
renderNode,
205-
})
206-
const style = props.node.style || 'normal'
207-
const handler =
208-
typeof components.block === 'function' ? components.block : components.block[style]
209-
const Block = handler || components.unknownBlockStyle
210-
211-
if (Block === components.unknownBlockStyle) {
212-
handleMissingComponent(unknownBlockStyleWarning(style), {
213-
nodeType: 'blockStyle',
214-
type: style,
215-
})
216-
}
217-
218-
return <Block key={key} {...props} value={props.node} renderNode={renderNode} />
219-
}
220-
221140
function renderText(node: ToolkitTextNode, key: string) {
222141
if (node.text === '\n') {
223142
const HardBreak = components.hardBreak
@@ -259,6 +178,170 @@ function getNodeRenderer (
259178
return renderNode
260179
}
261180

181+
function RenderList({
182+
renderNode,
183+
components,
184+
handleMissingComponent,
185+
node,
186+
index,
187+
}: {
188+
renderNode: NodeRenderer
189+
components: PortableTextReactComponents
190+
handleMissingComponent: MissingComponentHandler
191+
node: ReactPortableTextList
192+
index: number
193+
}) {
194+
const children = node.children.map((child, childIndex) =>
195+
renderNode({
196+
node: child._key ? child : {...child, _key: `li-${index}-${childIndex}`},
197+
index: childIndex,
198+
isInline: false,
199+
renderNode,
200+
}),
201+
)
202+
203+
const component = components.list
204+
const handler = typeof component === 'function' ? component : component[node.listItem]
205+
const List = handler || components.unknownList
206+
207+
if (List === components.unknownList) {
208+
const style = node.listItem || 'bullet'
209+
handleMissingComponent(unknownListStyleWarning(style), {
210+
nodeType: 'listStyle',
211+
type: style,
212+
})
213+
}
214+
215+
return (
216+
<List value={node} index={index} isInline={false} renderNode={renderNode}>
217+
{children}
218+
</List>
219+
)
220+
}
221+
222+
function RenderListItem({
223+
renderNode,
224+
components,
225+
handleMissingComponent,
226+
node,
227+
index,
228+
}: {
229+
components: PortableTextReactComponents
230+
handleMissingComponent: MissingComponentHandler
231+
renderNode: NodeRenderer
232+
node: PortableTextListItemBlock
233+
index: number
234+
}) {
235+
const tree = serializeBlock({node, index, isInline: false, renderNode})
236+
const renderer = components.listItem
237+
const handler = typeof renderer === 'function' ? renderer : renderer[node.listItem]
238+
const Li = handler || components.unknownListItem
239+
240+
if (Li === components.unknownListItem) {
241+
const style = node.listItem || 'bullet'
242+
handleMissingComponent(unknownListItemStyleWarning(style), {
243+
type: style,
244+
nodeType: 'listItemStyle',
245+
})
246+
}
247+
248+
let children = tree.children
249+
if (node.style && node.style !== 'normal') {
250+
// Wrap any other style in whatever the block serializer says to use
251+
const {listItem: _listItem, ...blockNode} = node
252+
children = renderNode({
253+
node: blockNode,
254+
index,
255+
isInline: false,
256+
renderNode,
257+
})
258+
}
259+
260+
return (
261+
<Li value={node} index={index} isInline={false} renderNode={renderNode}>
262+
{children}
263+
</Li>
264+
)
265+
}
266+
267+
function RenderSpan({
268+
renderNode,
269+
components,
270+
handleMissingComponent,
271+
node,
272+
}: {
273+
renderNode: NodeRenderer
274+
components: PortableTextReactComponents
275+
handleMissingComponent: MissingComponentHandler
276+
node: ToolkitNestedPortableTextSpan
277+
}) {
278+
const {markDef, markType, markKey} = node
279+
const Span = components.marks[markType] || components.unknownMark
280+
const children = node.children.map((child, childIndex) =>
281+
renderNode({
282+
node: child,
283+
index: childIndex,
284+
isInline: true,
285+
renderNode,
286+
}),
287+
)
288+
289+
if (Span === components.unknownMark) {
290+
handleMissingComponent(unknownMarkWarning(markType), {
291+
nodeType: 'mark',
292+
type: markType,
293+
})
294+
}
295+
296+
return (
297+
<Span
298+
text={spanToPlainText(node)}
299+
value={markDef}
300+
markType={markType}
301+
markKey={markKey}
302+
renderNode={renderNode}
303+
>
304+
{children}
305+
</Span>
306+
)
307+
}
308+
309+
function RenderBlock({
310+
renderNode,
311+
components,
312+
handleMissingComponent,
313+
node,
314+
index,
315+
isInline,
316+
}: {
317+
renderNode: NodeRenderer
318+
components: PortableTextReactComponents
319+
handleMissingComponent: MissingComponentHandler
320+
node: PortableTextBlock
321+
index: number
322+
isInline: boolean
323+
}) {
324+
const {_key, ...props} = serializeBlock({
325+
node,
326+
index,
327+
isInline,
328+
renderNode,
329+
})
330+
const style = props.node.style || 'normal'
331+
const handler =
332+
typeof components.block === 'function' ? components.block : components.block[style]
333+
const Block = handler || components.unknownBlockStyle
334+
335+
if (Block === components.unknownBlockStyle) {
336+
handleMissingComponent(unknownBlockStyleWarning(style), {
337+
nodeType: 'blockStyle',
338+
type: style,
339+
})
340+
}
341+
342+
return <Block {...props} value={props.node} renderNode={renderNode} />
343+
}
344+
262345
function serializeBlock(options: Serializable<PortableTextBlock>): SerializedBlock {
263346
const {node, index, isInline, renderNode} = options
264347
const tree = buildMarksTree(node)

0 commit comments

Comments
 (0)