Skip to content
On this page

如何写好条件渲染

jsx 中编写条件渲染,很多人往往使用三元运算符号,当条件复杂时,三元运算符会难以阅读,导致我们的 jsx 也难以阅读。

今天就来谈谈有哪些方式写出干净的、可读性好的条件渲染。

提前返回

jsx
function ListPage() {
  const { data, error, isLoading } = useGetData()

  if (isLoading) {
    return (
      <Layout>
        <LoadingSpinner />
      </Layout>
    )
  }

  if (error) {
    return (
      <Layout>
        <ErrorMessage message={error.message} />
      </Layout>
    )
  }

  return (
    <Layout>
      {data.items.map(item => (
        <Item key={item.id} item={item} />
      ))}
    </Layout>
  )
}

Layout重复:

jsx
function ListPage() {
  const { data, isLoading } = useGetData()

  if (isLoading) {
    return (
      <Layout>
        <LoadingSpinner />
        <MoreComponents>
          {
            //... more components here
          }
        </MoreComponents>
      </Layout>
    )
  }

  return (
    <Layout>
      {data.items.map(item => (
        <Item key={item.id} item={item} />
      ))}
      <MoreComponents>
        {
          //... more components here
        }
      </MoreComponents>
    </Layout>
  )
}

MoreComponents 还是重复,继续优化:

jsx
export function ItemList() {
  const { data, error, isLoading } = useGetData()

  if (isLoading) {
    return <LoadingSpinner />
  }

  return data.items.map(item => <Item key={item.id} item={item} />)
}

export function ListPage() {
  return (
    <Layout>
      <ItemList />
      <MoreComponents>
        {
          //... more components here
        }
      </MoreComponents>
    </Layout>
  )
}

返回 null

jsx
export function ItemList({ items }) {
  return items.map(item => <Item key={item.id} item={item} />)
}

function ListPage() {
  const { data } = useGetData()
  return <Layout>{!!data?.items && <ItemList items={data.items} />}</Layout>
}

ListPage 可读性还是不高,继续优化:

jsx
export function ItemList({ items }) {
  if (!items) {
    return null
  }

  return items.map(item => <Item key={item.id} item={item} />)
}

function ListPage() {
  const { data } = useGetData()
  return (
    <Layout>
      <ItemList items={data?.items} />
    </Layout>
  )
}

再优化:

jsx
export function ItemList({ isHidden }) {
  const { data } = useGetData()

  if (isHidden) {
    return null
  }

  return data.items.map(item => <Item key={item.id} item={item} />)
}

function ListPage({ isItemListHidden }) {
  return (
    <Layout>
      <ItemList isHidden={isItemListHidden} />
    </Layout>
  )
}

可选链操作符

jsx
function ListPage() {
  // data.tags may be null or undefined
  const { data } = useGetData()

  return (
    <Layout>
      <Post post={data.post} />
      {data.tags?.map(tag => (
        <Tag key={tag.id} tags={tag} />
      ))}
    </Layout>
  )
}

渲染变量

jsx
function ListPage() {
  const { data, isLoading } = useGetData()

  let content = <LoadingSpinner />
  if (!isLoading) content = data.items.map(item => <Item key={item.id} item={item} />)

  return <Layout>{content}</Layout>
}

三元操作符结合变量:

jsx
function ListPage() {
  const { data, isLoading } = useGetData()

  const content = isLoading ? <LoadingSpinner /> : data.items.map(item => <Item key={item.id} item={item} />)

  return <Layout>{content}</Layout>
}

component map / 枚举

jsx
const components = {
  loading: <LoadingSpinner />,
  error: <ErrorMessage />,
  success: <ItemList />,
}

function ListPage() {
  const { status } = useGetData()

  return <Layout>{components[status]}</Layout>
}

传递参数:

jsx
const components = {
  loading: () => <LoadingSpinner />,
  error: ({ error }) => <ErrorMessage message={error.message} />,
  success: ({ data }) => <ItemList items={data.items} />,
}

function ListPage() {
  const { data, error, status } = useGetData()
  return <Layout>{components[status]({ data, error })}</Layout>
}

参考

Conditional Rendering In React With A Focus On Readability And Clean Code

Released under the MIT License.