DEV Community

Cover image for Stop rendering conditions like this
abdelrahman seada
abdelrahman seada

Posted on • Edited on

851 4 11 11 15

Stop rendering conditions like this

we use conditions everywhere on our applications whether for state check or rendering some data into the view depending on some parameters. in this post will show some of how to render conditions in different way than using regular if(...) else {} blocks or even using ternary condition

for example (1)

type UserType = "admin" | "editor" | "user";

type User = { name: string; type: UserType };

const users: User[] = [
  { name: "john", type: "admin" },
  { name: "mike", type: "editor" },
  { name: "abdelrahman", type: "user" },
];

export default function Test() {
  const actions = ["create", "read", "update", "delete"];

  return (
    <div>
      {users.map((user) => (
        <div key={user.name}>
          {/* we need to render actions depending on user type */}
          <p>{user.name}</p>
          <div className="flex items-center">
            user actions:
            {user.type === "admin" && actions.map((a) => <Action a={a} key={a} />)}
            {user.type === "editor" && actions.filter((a) => a !== "create").map((a) => <Action a={a} key={a} />)}
            {user.type === "user" && actions.filter((a) => a === "read").map((a) => <Action a={a} key={a} />)}
          </div>
        </div>
      ))}
    </div>
  );
}

function Action(props: { a: string }) {
  const { a } = props;
  return <p className="px-2 py-1 border-[1px] mx-2 rounded-md">{a}</p>;
}


Enter fullscreen mode Exit fullscreen mode

output for example (1)

rendering using regular method

in this example we had to make a check condition for each user type to render his actions, as you can see this consumes a lot of code , harder to debug , harder to add more in future lastly looks ugly but this is a better way to do so

example (2)

type UserType = "admin" | "editor" | "user";

type User = { name: string; type: UserType };

const users: User[] = [
  { name: "john", type: "admin" },
  { name: "mike", type: "editor" },
  { name: "abdelrahman", type: "user" },
];

const userActionsStates: Record<UserType, string[]> = {
  admin: ["create", "read", "update", "delete"],
  editor: ["create", "read", "update"],
  user: ["read", "update"],
};

export default function Test() {
  return (
    <div>
      {users.map((user) => (
        <div key={user.name}>
          {/* we need to render actions depending on user type */}
          <p>{user.name}</p>
          <div className="flex items-center">
            user actions:
            {userActionsStates[user.type].map((a) => (
              <Action key={a} a={a} />
            ))}
          </div>
        </div>
      ))}
    </div>
  );
}

function Action(props: { a: string }) {
  const { a } = props;
  return <p className="px-2 py-1 border-[1px] mx-2 rounded-md">{a}</p>;
}


Enter fullscreen mode Exit fullscreen mode

output for example (2)

  • output is the same as example (1)

key changes

grouping each user type in object key and value should be what ever you want to render
in this case we pass each user type actions like the following

grouping in objects

and here instead of rendering each condition like example (1) or making a ternary condition we get user actions from grouped object userActionsStates and just render whatever in the key's value and Voilà it's only one line of code

conditions using object

what about else ? what if we pass a user type that does not exists in the object ?

in this case we can add a default key in the object , this key will be used in false or undefined cases
like the following :


const userActionsStates : Record<UserType , string[] > = {
    admin: ["create", "read", "update", "delete"],
    editor: ["create", "read", "update"],
    user: ["read", "update"],
    default : ["read"]
}


Enter fullscreen mode Exit fullscreen mode

if we updated users with new user that it's type is not defined like the last user object

updated users with new undefined user type

then we will make a small change to the render method

<div className="flex items-center">
  user actions:
  {(userActionsStates[user.type] ?? userActionsStates["default"]).map((a) => (
    <Action key={a} a={a} />
  ))}
</div>

Enter fullscreen mode Exit fullscreen mode

using null coalescing ?? we ensure that it will render as expected on
all conditions. :)

updated users output

please note

using this method you can render anything in the key's value string , number , array , Component , ...etc.

summary

  • easy to read , debug and update 🧑‍💻
  • looks cool 😌
  • less code

it's up to your creativity and imaginations 💡🔥

SurveyJS custom survey software

JavaScript UI Libraries for Surveys and Forms

SurveyJS lets you build a JSON-based form management system that integrates with any backend, giving you full control over your data and no user limits. Includes support for custom question types, skip logic, integrated CCS editor, PDF export, real-time analytics & more.

Learn more

Top comments (67)

Collapse
 
shricodev profile image
Shrijal Acharya • Edited

Just one simple piece of advice: Instead of using 4 spaces for indentation in code snippets for blogs, I think it's better to use 2 spaces as it reduces the need for horizontal scrolling.

Great read. 👌

Collapse
 
abdoseadaa profile image
abdelrahman seada

thanks for this advice 🤍

Collapse
 
johnysavestheworld profile image
John

How about using the tab character? That what it is meant for and every one can set the space to what ever fits best for one.

Collapse
 
bop profile image
bop

github.com/gvergnaud/ts-pattern

this is also a good alternative

Collapse
 
alexmorgun profile image
Alexander Morgun

As always, all gold is in comments :)

Collapse
 
abdoseadaa profile image
abdelrahman seada

will try it thanks 💕

Collapse
 
mttdevbr profile image
mttdev-br

beautiful stuff! rust inspired, perhaps?

Collapse
 
kristofajosh profile image
KristofaJosh

Nice read!! a little improvement for the action array.

const actions = {
  create: 'create',
  read: 'read',
  update: 'update',
  delete: 'delete',
} as const;
Enter fullscreen mode Exit fullscreen mode

create a type of actions

type Actions = (typeof actions)[keyof typeof actions];
Enter fullscreen mode Exit fullscreen mode

then

const userActionsStates : Record<UserType , Actions[] > = {
    admin: ["create", "read", "update", "delete"], // action.create | action.delete
    editor: ["create", "read", "update"],
    user: ["read", "update"],
    default : ["read"]
}
Enter fullscreen mode Exit fullscreen mode

Voila!
no one should add something weird within 😏
...

Collapse
 
abdoseadaa profile image
abdelrahman seada

that's a great one thanks

Collapse
 
anhpw profile image
Brian Cao • Edited

My approaching as following

/**
 * You declare the data in type of array
 * Then, you can loop through the list when you neeed
 */

const ACTIONS = ['create', 'read', 'update', 'delete'] as const
const USER_TYPES = ['admin', 'editor', 'user', 'anonymous'] as const

/**
 * Types guard
 */
type Action = typeof ACTIONS[number]
type UserType = typeof USER_TYPES[number]

/**
 * Your userActions data with types guard
 */
const userActions : Record<UserType , Action[] > = {
    admin: ["create", "read", "update", "delete"],
    editor: ["create", "read", "update"],
    user: ["read", "update"],
    anonymous: ["read"]
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
abdoseadaa profile image
abdelrahman seada

good one too ⭐

Collapse
 
abdoseadaa profile image
abdelrahman seada • Edited

didn't expect that anyone would see this post
cat meme

Collapse
 
mshossain110 profile image
Shahadat Hossain

I think this is not a matter of condition. It's a matter of good practice. Example 1 is easy to understand for beginners, but the other one is good to maintain and easy to extend.

Collapse
 
abdoseadaa profile image
abdelrahman seada

it's a better way to write conditions as you said easy to maintain , extend and debug

Collapse
 
aayushgoyal profile image
Aayush Goyal

Little things like these make you a pro developer. All the best to everyone and thanks to the author for sharing a good and short article.

Collapse
 
abdoseadaa profile image
abdelrahman seada

awesome comment award 🌃⭐

Collapse
 
abdulrhmanmoha profile image
abdulrhman-moh

this is awesome

Collapse
 
abdoseadaa profile image
abdelrahman seada

you are awesome

Collapse
 
tahdiislam profile image
Tahdi Islam

Valuable, Thanks for sharing

Collapse
 
hamdi4beep profile image
Hamdi Kamel

This is great!

You get to simplify things further by creating objects with properties that point to specific values instead of checking nonstop for multiple values.

Collapse
 
abdoseadaa profile image
abdelrahman seada

that's exactly it

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay