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>;
}
output for example (1)
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>;
}
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
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
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"]
}
if we updated users with new user that it's type is not defined like the last user object
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>
using null coalescing
??
we ensure that it will render as expected on
all conditions. :)
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
Top comments (54)
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. ๐
thanks for this advice ๐ค
github.com/gvergnaud/ts-pattern
this is also a good alternative
will try it thanks ๐
As always, all gold is in comments :)
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.
it's a better way to write conditions as you said easy to maintain , extend and debug
this is awesome
you are awesome
didn't expect that anyone would see this post
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.
that's exactly it
Really Great Approach, Surely i am going to use in my Project, Awsome Thanks!
that's awesome, have a good one
Thank you for posting, I am aspiring to be able to write and understand fluently! Reading these articles from inside perspectives helps tremendously!
glad to hear that ๐ค
There is nothing wrong with conditions, you just reshaped the data you are working with
exactly, there is nothing wrong with conditions anyways , it's just a better approach
Amazing tip!
thanks <3