대형 구성 요소의 간소화 능력
57040 단어 reactwebdevjavascriptnode
대형 구성 요소를 가지고 있는 것이 항상 나쁜 것은 아니지만, 구성 요소를 더욱 간소화할 수 있는 기회를 이용하는 것은 특히 추가적인 이익을 제공할 때 좋은 방법이다.
큰 구성 요소가 있을 때 불리해질 수 있습니다. 구성 요소가 클수록 시간의 흐름에 따라 유지보수와 읽기가 어려워집니다.
아래의 이 구성 요소를 살펴보고 왜 간소화하는 것이 더 좋은지 봅시다.
(이것은 생산 응용 프로그램의 코드이기 때문에 이것은 사실상 진실한 예이다)
다음 구성 요소
SidebarSection
은 일부 도구를 사용했는데 그 중에서 props.ids
은 하나의 항목 ID 그룹을 문자열로 하고 props.items
은 하나의 대상으로 각 항목의 id
을 키맵 사이드바 항목으로 사용한다.다음 도구를 사용하여 사이드바 항목을 렌더링합니다.import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
import List from '@material-ui/core/List'
import Divider from '@material-ui/core/Divider'
import ListSubheader from '@material-ui/core/ListSubheader'
import { EDIT_NOTEBOOK, DELETE_NOTEBOOK } from 'features/toplevel'
import { selectSelected } from 'features/sidebar'
import SidebarContext from './SidebarContext'
import SidebarItem from './SidebarItem'
function SidebarSection({ id: sectionId, ids, items, depth, expanded }) {
const ctx = React.useContext(SidebarContext)
const selectedId = useSelector(selectSelected)
if (!ctx) return null
return (
<List dense={depth > 0} disablePadding>
{ids.map((id: string, itemIndex: number) => {
const key = `SidebarSection_${id}_item${itemIndex}`
const item = items[id]
switch (item.type) {
case 'divider':
return <Divider key={key} style={{ padding: 0, margin: 0 }} />
case 'label':
return (
<ListSubheader
key={key}
style={{
transform: expanded ? undefined : 'scale(0.55)',
textOverflow: 'ellipsis',
overflow: 'hidden',
userSelect: 'none',
}}
disableGutters={!expanded}
>
{item.label}
</ListSubheader>
)
case 'notebook': {
// Called inside unserializeHoverControlsProps when iterating over each hover action
const onHoverAction = (action: any) => {
if (action.Icon) {
const notebook = item.data
if (notebook) {
action.onClick = ctx.createHoverControlsActionOnClick({
context:
action.name === 'edit'
? EDIT_NOTEBOOK
: action.name === 'delete'
? DELETE_NOTEBOOK
: '',
data:
action.name === 'edit'
? item
: action.name === 'delete'
? {
id: notebook.id,
title: notebook.info.title,
description: notebook.info.description,
isEncrypt: notebook.isEncrypt,
created_at: notebook.created_at,
modified_at: notebook.modified_at,
}
: null,
})
}
}
}
return (
<SidebarItem
key={key}
sectionId={sectionId}
depth={depth}
item={ctx.unserializeItem(item, { onHoverAction })}
isSelected={item.id === selectedId}
{...ctx}
/>
)
}
case 'static':
return (
<SidebarItem
key={key}
sectionId={sectionId}
depth={depth}
item={ctx.unserializeItem(item)}
isSelected={item.id === selectedId}
{...ctx}
/>
)
default:
return null
}
})}
</List>
)
}
구성 요소가 실제로는 그렇게 나쁘게 보이지는 않지만, 우리가 구성 요소를 편집할 때마다, 변경 사항을 도입하기 전에 줄마다 코드를 이해해야 한다. 왜냐하면 어떤 내용을 바꾸면 구성 요소의 다른 부분을 파괴할지 모르기 때문이다.예를 들어 스위치 박스에 생성된
onHoverAction
함수입니다.이것은 우리의 구성 요소를 불필요하게 팽창시켰고 SidebarItem
의 실현에 달려 있다. 구성 요소가 다시 렌더링될 때마다 인용을 다시 만들 수 있기 때문에 무한 순환을 초래할 수 있다.이것 또한 전체 구성 요소가 단원 테스트에 더욱 민감하게 한다. 왜냐하면 우리는
SidebarSection
구성 요소에 onHoverAction
의 실현 세부 사항을 책임지도록 권한을 부여했기 때문이다.우리의 단원 테스트에서 onHoverAction
구성 요소의 행위가 정확한지 테스트할 때 우리는 SidebarSection
의 실현 세부 사항을 알아야 한다. 이것은 큰 의미가 없다. (이것은 문법 오류와 같은 일에 주의해야 한다는 것을 의미한다. 함수의 입력 오류가 SidebarSection
의 표현을 파괴할 수 있기 때문에 우리는 이 구성 요소가 잘하지 못했다고 탓할 것이다)단순히 외부로 추출하여 프로세스를 단순화할 수 있으므로 더 이상 구성 요소 탓으로 돌릴 필요가 없습니다.
function onHoverAction(item, createOnClick) {
return (action) => {
if (action.Icon) {
const notebook = item.data
if (notebook) {
action.onClick = ctx.createHoverControlsActionOnClick({
context:
action.name === 'edit'
? EDIT_NOTEBOOK
: action.name === 'delete'
? DELETE_NOTEBOOK
: '',
data:
action.name === 'edit'
? item
: action.name === 'delete'
? {
id: notebook.id,
title: notebook.info.title,
description: notebook.info.description,
isEncrypt: notebook.isEncrypt,
created_at: notebook.created_at,
modified_at: notebook.modified_at,
}
: null,
})
}
}
}
}
function SidebarSection({ id: sectionId, ids, items, depth, expanded }) {
const ctx = React.useContext(SidebarContext)
const selectedId = useSelector(selectSelected)
if (!ctx) return null
return (
<List dense={depth > 0} disablePadding>
{ids.map((id: string, itemIndex: number) => {
const key = `SidebarSection_${id}_item${itemIndex}`
const item = items[id]
switch (item.type) {
case 'divider':
return <Divider key={key} style={{ padding: 0, margin: 0 }} />
case 'label':
return (
<ListSubheader
key={key}
style={{
transform: expanded ? undefined : 'scale(0.55)',
textOverflow: 'ellipsis',
overflow: 'hidden',
userSelect: 'none',
}}
disableGutters={!expanded}
>
{item.label}
</ListSubheader>
)
case 'notebook': {
return (
<SidebarItem
key={key}
sectionId={sectionId}
depth={depth}
item={ctx.unserializeItem(item, {
onHoverAction: onHoverAction(
item,
ctx.createHoverControlsActionOnClick,
),
})}
isSelected={item.id === selectedId}
{...ctx}
/>
)
}
case 'static':
return (
<SidebarItem
key={key}
sectionId={sectionId}
depth={depth}
item={ctx.unserializeItem(item)}
isSelected={item.id === selectedId}
{...ctx}
/>
)
default:
return null
}
})}
</List>
)
}
우리가 하는 일은 단지 이 기능을 다른 곳으로 옮기는 것일 뿐이다. 그것은 우리에게 커다란 이익을 가져다 주었고, 거의 어떠한 추가 노력도 필요없다.SidebarSection
은 이제 평온한 생활을 할 수 있다. 왜냐하면 onHoverAction
을 정확하게 실현할 염려가 없기 때문이다.그것이 해야 할 일은 onHoverAction
이 기대하는 파라미터를 전달하는 것이다.onHoverAction
에 대해 단원 테스트를 진행할 수 있다. 왜냐하면 이것은 수출 제품으로 제공할 수 있기 때문이다.이게 기대한 효과에 도달할 수 있는지 보고 싶으세요?그것을 가져오고 세 개의 인자를 입력한 다음 무엇을 되돌려주는지 확인하십시오.SidebarSection
은 읽기와 관리가 더욱 쉬워졌습니다.case 'notebook':
return (
<SidebarItem
key={key}
sectionId={sectionId}
depth={depth}
item={ctx.unserializeItem(item, {
onHoverAction: onHoverAction(
action,
item,
ctx.createHoverControlsActionOnClick,
),
})}
isSelected={item.id === selectedId}
{...ctx}
/>
)
case 'static':
return (
<SidebarItem
key={key}
sectionId={sectionId}
depth={depth}
item={ctx.unserializeItem(item)}
isSelected={item.id === selectedId}
{...ctx}
/>
)
사실상 현 상태를 유지하는 것은 큰 문제가 되지 않을 것이다.그러나 나는 이 코드를 읽는 개발자는 모든 도구를 한 줄 한 줄 읽을 의무가 있다고 믿는다. 단지 100% 그것들이 그다지 다르지 않다는 것을 확보하기 위해서이다.이상적인 상황에서 우리는 비슷한 코드가 분리되는 중요한 원인이 있다고 믿기를 바란다. 그렇다면 왜 이런 코드가 분리될까?우리의 예에서 좋은 이유가 많지 않기 때문에 이 과정을 간소화하는 것은 좋은 생각이다. 그러면 장래의 개발자들이 이 구성 요소를 디버깅할 때 이런 어색한 상황에 빠지지 않을 것이다.
우리는 간단한 조작을 통해 다음과 같은 간소화를 할 수 있다.
case 'notebook':
case 'static':
return (
<SidebarItem
key={key}
sectionId={sectionId}
depth={depth}
item={ctx.unserializeItem(item, item.type === 'notebook' ? {
onHoverAction: onHoverAction(
action,
item,
ctx.createHoverControlsActionOnClick,
),
} : undefined)}
isSelected={item.id === selectedId}
{...ctx}
/>
)
이를 단순화하면 다음과 같은 두 가지 중요한 이점이 있습니다.'notebook'
의 항목을 제외하고 'static'
의 항목을 클릭하면 안 된다. 이들의 차이를 너무 걱정할 필요가 없다) 간소화와 과도한 사고가 그 반대일 때
현재 우리가 간소화할 수 있는 몇 가지 물건들이 있다.비록 우리의 스위치 박스가 조금 짧아졌지만, 보기에는 좀 보기 흉하다.이것이 바로 Dell의
SidebarSection
구성 요소가 변경된 단순화를 적용한 후의 모습입니다.function SidebarSection({ id: sectionId, ids, items, depth, expanded }) {
const ctx = React.useContext(SidebarContext)
const selectedId = useSelector(selectSelected)
if (!ctx) return null
return (
<List dense={depth > 0} disablePadding>
{ids.map((id: string, itemIndex: number) => {
const key = `SidebarSection_${id}_item${itemIndex}`
const item = items[id]
switch (item.type) {
case 'divider':
return <Divider key={key} style={{ padding: 0, margin: 0 }} />
case 'label':
return (
<ListSubheader
key={key}
style={{
transform: expanded ? undefined : 'scale(0.55)',
textOverflow: 'ellipsis',
overflow: 'hidden',
userSelect: 'none',
}}
disableGutters={!expanded}
>
{item.label}
</ListSubheader>
)
case 'notebook':
case 'static':
return (
<SidebarItem
key={key}
sectionId={sectionId}
depth={depth}
item={ctx.unserializeItem(
item,
item.type === 'notebook'
? {
onHoverAction: onHoverAction(
action,
item,
ctx.createHoverControlsActionOnClick,
),
}
: undefined,
)}
isSelected={item.id === selectedId}
{...ctx}
/>
)
default:
return null
}
})}
</List>
)
}
우리가 직면할 수 있는 문제는 모든 프로젝트의 렌더링 블록에 너무 많은 책임을 부여하고 정확한 도구를 정확한 구성 요소에 전달하도록 하는 것이다.이런 관점에서 보면 이런 방식으로 다시 쓰는 것이 더 좋을 것이다.
function getProps({ item, expanded, sectionId, selectedId, depth, ctx }) {
switch (item.type) {
case 'divider':
return { style: { padding: 0, margin: 0 } }
case 'label':
return {
style: {
transform: expanded ? undefined : 'scale(0.55)',
textOverflow: 'ellipsis',
overflow: 'hidden',
userSelect: 'none',
},
disableGutters: !expanded,
}
case 'notebook':
case 'static':
return {
sectionId,
depth,
item: ctx.unserializeItem(
item,
item.type === 'notebook'
? {
onHoverAction: onHoverAction(
item,
ctx.createHoverControlsActionOnClick,
),
}
: undefined,
),
isSelected: item.id === selectedId,
...ctx,
}
default:
return undefined
}
}
function SidebarSection({ id: sectionId, ids, items, depth, expanded }) {
const ctx = React.useContext(SidebarContext)
const selectedId = useSelector(selectSelected)
if (!ctx) return null
return (
<List dense={depth > 0} disablePadding>
{ids.map((id: string, itemIndex: number) => {
const key = `SidebarSection_${id}_item${itemIndex}`
const item = items[id]
let Component
if (item.type === 'divider') {
Component = Divider
} else if (item.type === 'label') {
Component = ListSubheader
} else if (['notebook', 'static'].includes(item.type)) {
Component = SidebarItem
} else {
return null
}
return (
<Component
key={key}
{..getProps(
item,
expanded,
sectionId,
selectedId,
depth,
ctx
})}
/>
)
})}
</List>
)
}
이제 SidebarSection
을 단순화하고 getProps
에 전화를 걸어 관련 도구를 제공하고 Component
에 따라 정확한 item.type
을 분배하는 일만 맡게 되었습니다.우리는 현재 getProps
에 대해 단원 테스트를 실시하여 그들이 item.type
에 따라 정확한 아이템을 반환할 수 있도록 확보할 수 있다.이것은 React 코드를 간소화하는 좋은 시도입니까?이점과 단점을 살펴보겠습니다.
이점:
SidebarSection
은 직책을 줄였다.SidebarSection
이 작아졌습니다.key={key}
에서 4번 통과할 필요 없이 <Component key={key}
처럼 통과할 수 있습니다.SidebarSection
은 작아졌지만 파일은 커졌습니다.SidebarSection
내부)가 세 개의 실체(현재 각각 SidebarSection
, onHoverAction
, getProps
)로 바뀌었다.그렇게 가치가 있습니까?
내가 보기에, 만약 마지막 부분을 하는 데 너무 오래 걸린다면, 그것은 가치가 없을 것이다.이 이야기는 코드를 간소화하는 것이 절대적으로 가치가 있다는 뜻이다. 왜냐하면 너무 많은 노력이 필요하지 않지만, 결과적으로 더 많은 이익을 제공할 수 있기 때문이다.
그러므로 우리의 글에서 나는 본문의 앞의 두 가지 간소화 시도를 지지하고 세 번째 시도는 약간 망설인다.
그러나, 우리는 현재react에서 대형 구성 요소를 간소화하는 능력을 보았다.
결론
이 글은 이것으로 끝냅니다!나는 네가 이것이 가치가 있다는 것을 발견하고 미래에 더욱 많은 것을 기대하길 바란다.
medium으로 전화해 주세요.
Reference
이 문제에 관하여(대형 구성 요소의 간소화 능력), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/jsmanifest/the-power-of-simplifying-large-components-in-react-583k텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)