DEV Community

Yoshihiro Nakamura
Yoshihiro Nakamura

Posted on • Edited on

Just one line code that will cleanup your jsx

You might have seen the code like:

function Profile() {
  const [res] = useQuery({ query: GetCurrentUser })

  return (
    <div>
      {res.fetching && <Spinner />}
      {res.error && <p>error</p>}
      {res.data?.currentUser && (
        <div>
          <Avatar name={res.data.currentUser.name} size="l" />
          <p>{res.data.currentUser.name}</p>
          <p>{res.data.currentUser.email}</p>
          <p>{res.data.currentUser.age}</p>
        </div>
      )}
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

Here, res.data.currentUser is used over time. How can we make it cleaner?

Extracting to another component (e.g. ProfileCard) is definitely a solution. But sometimes we want to keep it in one component.

Or you can reassign it to a variable:

function Profile() {
  const [res] = useQuery({ query: GetCurrentUser })

  if (res.fetching) return <Spinner />

  if (res.error || !res.data) return <p>error</p>

  const { currentUser } = res.data

  return (
    <div>
      {currentUser && (
        <div>
          <Avatar name={currentUser.name} size="l" />
          <p>{currentUser.name}</p>
          <p>{currentUser.email}</p>
          <p>{currentUser.age}</p>
        </div>
      )}
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

Looks better, but you should change the other things like res.fetching and res.error (otherwise TypeScript gonna shout at you). And sometimes we want render h1 without waiting response from api.

better approarch: fromObject

So what we wanted to achieve in the first place?

{res.data?.currentUser && (
  <div>
    <Avatar name={res.data.currentUser.name} size="l" />
    <p>{res.data.currentUser.name}</p>
    <p>{res.data.currentUser.email}</p>
    <p>{res.data.currentUser.age}</p>
  </div>
)}
Enter fullscreen mode Exit fullscreen mode

In order to reduce abundant res.data.currentUser, we'd like to have code that if res.data.currentUser exists, assign or spread temporarily and use it to return jsx.

And you can do this with just a one lines of code:

export const fromObject = (obj) => (cb) => cb(obj)
Enter fullscreen mode Exit fullscreen mode

in TypeScript:

export function fromObject<T extends Record<string, unknown>>(
  obj: T
): <R>(fn: (obj: T) => R) => R {
  return (fn) => fn(obj)
}
Enter fullscreen mode Exit fullscreen mode

Then use it to clean up the code:

{res.data?.currentUser &&
  fromObject(res.data.currentUser)(({ name, email, age }) => (
    <div>
      <Avatar name={name} size="l" />
      <p>{name}</p>
      <p>{email}</p>
      <p>{age}</p>
    </div>
))}
Enter fullscreen mode Exit fullscreen mode

Tada! looks way nicer, uh?

Though it's a simple solution, I've never seen in my more than 5 years of career as a React developer.
If you've done with similar solution or if you have any concerns, please let me know!

Top comments (0)