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>
)
}
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>
)
}
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>
)}
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)
in TypeScript:
export function fromObject<T extends Record<string, unknown>>(
obj: T
): <R>(fn: (obj: T) => R) => R {
return (fn) => fn(obj)
}
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>
))}
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)