DEV Community

Cover image for Rethinking How we write JSX in React - Part 1
Ashish Prajapati
Ashish Prajapati

Posted on • Edited on

Rethinking How we write JSX in React - Part 1

Note:- This is an attempt of mine to make JSX more readable and maintanable.

Introduction

We all have always been run into some un-canny ways for writing the conditional jsx. Whether its ternary hell, short-circuit hell, or switch object to render specific component with key, or rendering the async list(array) with Arr.length > 0 && Arr.map something like that and so on...

What if there was a way to solve these?!

Yes there is!!!

But, first let's take a closer look at the problems which I am talking about. See the below examples.

Current problems in JSX that we write


1. Ternary and short-circuting problem

function Dashboard() {
    const [showUser, setShowUser] = useState(false)

    return (
        <div>
            {/* Based on flag, show the content */}
            {/* If no fallback needed */}
            {showUser && <div>User modal component</div>}

            {/* If fallback needed. */}
            {/* This gets unreable if jsx is bigger than 5-10 lines */}
            {showUser ? <div>User modal component</div> : <div>some other thing</div>}
        </div>
    )
}
Enter fullscreen mode Exit fullscreen mode

2. Sync/Async list rendering

function List() {
    const [notes, setNotes] = useState<{ id: number, title: string }[]>([])

    useEffect(() => {
        // assume, notes are coming from api
        setNotes([
            { id: 1, title: 'some random' }, 
            { id: 2, title: "awesome" }
        ])
    }, [])

    return (
        <ul>
            {/* rendering notes */}
            {/* manually checking the length and running map function. */}
            {/* Which already look too repetitive and cumbersome to write often */}
            {notes.length > 0 && notes.map((item) => {
                return (
                    <li>{item.id} - {item.title}</li>
                )
            })}
        </ul>
    )
}
Enter fullscreen mode Exit fullscreen mode

3. Switching object problem

function Switch(){
    const userStatus: "Banned"|"Online"|"InActive" = "Online" 

    // This is often created to manage switch based logic.
    // Which just creates two twisted sources for jsx. 
    // it always become un-managable by managing two seperate types
    const StatusComponent = {
        "Banned": ()=><div>banned status component</div>,
        "Online": ()=><div>online status component</div>,
        "InActive": ()=><div>in-active status component</div>,
    }
    const ActiveStatus = StatusComponent[userStatus]

    return (
        <div>
            {/* Showing different status component based on the user status */}
            {<ActiveStatus />}
        </div>
    )
}
Enter fullscreen mode Exit fullscreen mode

I am pretty sure, you have written these kind of code. Most of the time it's un-avoidable.

So to solve these, I have created my own npm library classic-react-components.

Before explaining about it, let's first take a look on how this library solve all of these things. See below examples which are used to tackle out those conditional things.

How I have tried to solve them


1. If-Else component -> Replacing ternary and short-circuit with

import {If, Then, Else} from 'classic-react-components'

function Dashboard() {
    const [showUser, setShowUser] = useState(false)

    return (
        <div>
            {/* No ternary for simple toggling. Use if-else */}
            <If condition={showUser}>
                <Then>
                    <div>User modal component</div>
                </Then>
            </If>


            {/* Use if-else syntax */}
            <If condition={showUser}>
                <Then>
                    <div>User modal component</div>
                </Then>
                <Else>
                    <div>some other thing</div>
                </Else>
            </If>
        </div>
    )
}
Enter fullscreen mode Exit fullscreen mode

2. For component -> Solving sync/async list rendering


function List() {
    const [notes, setNotes] = useState<{ id: number, title: string, description?: string }[]>([])

    useEffect(() => {
        // assume, notes are coming from api
        setNotes([{ id: 1, title: 'some random' }, { id: 2, title: "awesome" }])
    }, [])

    return (
        <ul>
            {/* rendering notes */}
            {/* No undefine check or Array.map */}
            {/* Fully type-safe */}
            <For data={notes}>
                {(item, index)=> <li key={index}>{item.id} - {item.title}</li>}
            </For>
        </ul>
    )
}
Enter fullscreen mode Exit fullscreen mode

3. Switch-Case component -> Solving switching of object

function Switch(){
    const userStatus: "Banned"|"Online"|"InActive" = "Online" 

    return (
        <div>
            {/* No type needed, using infering  */}
            <Switch item={userStatus}>
                {({ Case, Default }) => {
                    return (
                        <>
                            {/*  value is type-safe */}
                            <Case value='Banned'>
                                <div>banned status  component</div>
                            </Case>
                            <Case value='Online'>
                                <div>online status  component</div>
                            </Case>
                            <Case value='InActive'>
                                <div>in-active status  component</div>
                            </Case>

                            {/* put any where, ordering does not matter for <Default> */}
                            <Default>
                                <div>this is default case</div>
                            </Default>
                        </>
                    )
                }}
            </Switch>
        </div>
    )
}
Enter fullscreen mode Exit fullscreen mode

You already can see how our jsx becomes more readable, maintanable and fun to write. You can write if-else and switch-case code inside our jsx. That is so cool!!!

That's it for now. On next part, I will talk in-detail about all of the components.

Top comments (0)