What is the Prop Getters Pattern?

One of the advanced React patterns.

Elham Fadel Elshami
4 min readSep 20, 2022

--

Like every React developer who tends to improve productivity and write code that can be extended more than modified, I’d like to explain prop Getters Pattern.

But Because the majority of React developers prefer functional components, we will write React Component in this style.

So Let’s Go …

What is the Prop Getters Pattern?

Well, we all know that in Javascript all functions are objects. However, functions are built to be more customizable and reusable.

So I’ll try to rely on a simple example which is toggle button, but before we dive into it, let’s make sure we have the right information about first line.

Consider the following:

const object = {name: "Muhammad"}

We create one object with a constant value for the name property, but if we want to customize this object and create another we are forced to do that:

const createObject = value => ({name:value});
// now function can be called multiple times to create other object
const name2 = createObject("Adam");
const name3 = createObject("Youssef");

So, What about our pattern?

Prop getter pattern design is based on function, as mentioned previously functions can be customized therefore, using a prop getter allows for more interesting use cases.

Let’s see the code …

We have a custom hook called useToggle:

This hook will return an object containing isTogglestate, toggle(function to handle click event), and togglerProps which is an object that collects all props that I want to pass in the button component.

Then I import useToggle in the App.js and destruct the object:

We need isToggle boolean to make a conditional render that can control toggle of elements display.

If you notice I use spreadsyntax on line 7 to pass togglerProps object as props into the button.

Finally, I click on this button. I get:

Result after one click
Render element into the DOM

So How we can improve above code to be more powerful and customizable as you said?

If we convert togglerProps object to be function and called it getTogglerProps just for meaningful:

Now, we’ll call this function like a regular function:

And that’s it! The user’s app works just like before.

Wait Wait Wait … “the user’s app works like before!!”

So why do I bother myself??? Well, come with me!

For example, If we have this code from one of your teammates:

<button id="button_1" {...getTogglerProps()}>Click here</button>

Isn’t the IDpart of the button’s props?

Also, Look at this disaster 👇

<button id="button_1" {...getTogglerProps()}>Click here</button>
<button id="button_2" {...getTogglerProps()}>Click meee</button>
<button id="button_3" {...getTogglerProps()}>Click I see 😠</button>

So, How can give freedom and flexibility to add Additional props to the default props collection??

Well, we can pass all values as arguments:

<button {...getTogglerProps({id:"button_1"})}>Click here</button>

Then, let’s update getTogglerPropsfunction to cater to new props:

If you see we pass props as a parameter that holds all the custom props

Then spread all custom props into collection props.

Additional client props

Wow!! Did you see it? The IDpassed!!

One step away…

Now, what if the client wanted to pass in a custom onClick prop?

Like this:

<button
{...getTogglerProps({
id: "button_1",
onClick: () => alert("hello inside button 1")
})}
>
Click here
</button>
custom onClick prop

ًWhat happened? Isn’t the onClickhandler being updated?

Yes, when you do this you completely override the defaultonClick handler

because using spread operator will do updates for all togglerprops

Hmm, what we can do?

Actually to solve this problem we want to compose the default handler with the custom onClick handler so that both of these functions are called.

Look above ☝️ we create excuteFunctionsfunction that accepts any number of functions then to avoid neglecting the passed arguments we use this spread syntax (...args) .

So the result:

Result handling props

Yay, we did it 👏 👏 👏.

Conclusion

There are numerous basic and advanced patterns that can be used to create robust, reusable, and adaptable components.

--

--