대형 구성 요소의 간소화 능력

medium으로 전화해 주세요.
대형 구성 요소를 가지고 있는 것이 항상 나쁜 것은 아니지만, 구성 요소를 더욱 간소화할 수 있는 기회를 이용하는 것은 특히 추가적인 이익을 제공할 때 좋은 방법이다.
큰 구성 요소가 있을 때 불리해질 수 있습니다. 구성 요소가 클수록 시간의 흐름에 따라 유지보수와 읽기가 어려워집니다.
아래의 이 구성 요소를 살펴보고 왜 간소화하는 것이 더 좋은지 봅시다.
(이것은 생산 응용 프로그램의 코드이기 때문에 이것은 사실상 진실한 예이다)
다음 구성 요소 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'의 항목은 거의 똑같다. '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으로 전화해 주세요.
  • 좋은 웹페이지 즐겨찾기