Builders Wanted: Objects & Props

A junior web dev’s roadmap to the open web — part 2

Dawn Kelly
11 min readFeb 19, 2024

This is the second post of Builders Wanted, a learning series to help junior web developers sharpen their skills in the JavaScript and React concepts needed to build component widgets for the open web. You can still sign up to get email updates when new materials for this series drop.

Recap

The first step I took to prepare for React is to watch this video where As a Programmer shares ten JavaScript concepts they consider prerequisites to building with React. A less than ten-minute video isn’t going to have a ton of depth but it serves to help us decide what to focus on in the seemingly endless JavaScript universe.

Objects

In JavaScript, an object is a specific data type representing a value in memory. Objects allow us to create more complex data structures by combining state and behavior into a single value. As a reminder, state is a reflection of the current value of data used in the program. For example, in a game, your character may have 100 health points at the start of a battle. Suppose the character takes 20 damage from an attack. In that case, the ability of the program to know they should now have 80 health points remaining, and to update the current value accordingly, is a demonstration of statefulness. It’s important to know that React components re-render with state changes. Our BOS components will do the same thing but, I’ll cover that in more detail when we get there.

Behavior, on the other hand, is more about what the object does or can do. The available behaviors can be attached to specific states or changes in state. In our game scenario above, we might give the player different action options once their health points drop below a certain level, for example. You can also think about state managing behaviors as the way a website that requires registration will look different, and allow you to do different things (behavior), based upon whether or not you are logged in (state).

There are multiple ways to create objects however, for our eventual component building, we are going to focus on using object literal syntax. Per the MDN, an object literal is a list of zero or more pairs of property names and associated values of an object, enclosed in curly braces. Syntax to create a sample object can look like this:

const  myObject = {
propertyName1 : “property 1 value”,
propertyName2 : “property 2 value”,
propertyName3 : “property 3 value”
};

You may also see these properties all on one line. It’s dev preference as long as you put the properties inside the curly braces, separate each key/value pair with a colon, and separate each property with a comma. You can also nest objects (brackets within brackets) but we’ll visit that later.

Props

If you think of an object in JavaScript as a box, props (short for ‘properties’) are how we name and describe the collection of things inside the box. A property creates association between a key/name and value pair. The value can be any JavaScript value, and you’ll see them called methods if the value is a function. You may also see some attributes like “enumerable” or “writable” included. There are a few rules of the road you’ll want to know when working with props.

Props are not ordered, therefore you can’t access their value via indexing. There are two ways to access, modify, and add an object’s props; dot notation and bracket notation. Which one you’ll use depends on what you are trying to do. Both will allow you to access or modify the value of a property via its key. You can also use either method to add a new property to an object. Let’s take a look at a couple of examples to help us understand the syntax involved and when we want to use each of the two approaches. First, we’ll create a new object describing the current state of my work desk:

const myOffice = {
desk: “messy”,
laptop: “Macbook”,
pens: 8,
coffee: “empty”
};

If we wanted to know how many pens are in myOffice, we could use dot notation (object.key):

const howManyPens = myOffice.pens

would return 8.

We can also modify properties in our myOffice object using dot notation. For example, we could cure my sad coffee situation:

myOffice.coffee = “full”

It looks like I forgot to include my lucky Jonathan Marchessault signed hockey puck when I described the items in my office! We can use our dot notation to fix that as well.

myOffice.puck =  “Marchessault”

After all of these changes, our object and props now look like this:

const myOffice = {
desk: “messy”,
laptop: “Macbook”,
pens: 8,
coffee: “full”,
puck: “Marchessault”
};

Dot notation is what you’ll most commonly see when reading code, but it does have a couple of limitations. Dot notation can’t read property names with spaces or special characters. More importantly, dot notation can’t access properties dynamically.

Bracket notation helps us handle situations where we are accessing the object’s property using a variable. Let’s say I’m planning my trip to ETH Denver and I’m creating a checklist of things to pack so I don’t forget anything. In my office, I see my laptop. I definitely want to make sure that makes the list! I might use bracket notation so I can do something like:

const myOffice = {
desk: "messy",
laptop: "Macbook",
pens: 8,
coffee: "full",
puck: "Marchessault"
};


const packOffice = "laptop";
const mySuitcase = myOffice[packOffice];
console.log(mySuitcase)


// outputs Macbook

My main takeaway here is to know bracket notation is a thing. If you see spaces or special characters in a key, or if you’re getting an undefined error, try switching from dot to bracket notation and see if that corrects the issue.

Putting this all in the context of React components, props are used to pass data from one component to another. It’s important to note, the data flow with props is one-way only. Data can flow from a parent component to its children but never in the opposite direction. Props are necessary to create the dynamic outputs we want from our components. Let’s walk through an example where we use props to generate the content needed to create a pizza menu dynamically. I’m going to create this quick demo with NextJS as it’s the thing I know best. You can get an app up and running quickly with the Next docs or you can fork the repo for this demo. Node is the only dependency used.

For this example, we will assume two components: Menu and MenuItem. As you can see in the figure below, <Menu> will be a parent component which will contain the child component <MenuItem>. Looking at each menu item, we can see the names (or keys) of the props we’ll be assigning when we create our items.

Line diagram depicting a Menu component with multiple instances of Menu Item component embedded. Menu item includes properties: category, name, description, price, image.
Sketch of components

The first thing I’m going to do is create the data file for our menu items. You’ll notice my pizzaData object is set to an array and each item has an assigned ‘id’ value. This is because I’m going to use the array.map() method to render items from this list. We’ll have a more in-depth lesson on the map method in the future, just follow along for now.

const pizzaData = [
{
id: 1,
category: "meat",
name: "Pepperoni Pizzazz",
description: "A dazzling display of pepperoni majesty on a crispy crust",
price: "$15",
image: "/pepperoni.jpg",
alt: "pepperoni pizza"
},
{
id: 2,
category: "meat",
name: "Proud Pineapple",
description: "Pineapple definitely goes on pizza. It's ok to disagree, you're allowed to be wrong",
price: "$16",
image: "/pineapple.jpg",
alt: "pineapple pizza"
},
{
id: 3,
category: "vegetarian",
name: "Very Veggie",
description: "A collection of fresh veggies fit for a rabbit",
price: "$18",
image: "/veggie.jpg",
alt: "vegetable pizza"
}
]

Next, I’m going to create our MenuItem component which will form a template for rendering each item we add to pizzaData.js to our Menu view in the browser.

import pizzaData from '../pizzaData'
import Image from 'next/image'


const MenuItem = () => (
<div>
{pizzaData.map(item => (
<div key={item.id}>
<Image
src={item.image}
alt={item.alt}
width={240}
height={240}
/>
<h2>{item.name}</h2>
<p>{item.description}</p>
<h3>{item.price}</h3>
<span>{item.category}</span>
</div>
))}
</div>
)


export default MenuItem

A couple of things I want to mention right here. If you are wondering where “item” came from, I made it up. You can put anything you want in that spot. To me it makes sense to read this as “for each item in pizzaData, return these things” but I also see people use things like ‘e’ for events or elements and similar. It doesn’t matter. Just pick a name and be consistent. The second thing I want you to notice is the names you see after “item” match the names/keys of the props of our pizzaData objects. To finish things up, I’ll import the MenuItem component into the Menu component and, finally, the Menu component into our page.js file so it renders on the homepage.

Screenshot of the pizza menu showing two types of pizza along with names, descriptions, prices, and categories.
Tada! We made a thing!

I want to show you the Menu component here so I can point out one more thing:

import MenuItem from "./MenuItem"


const Menu = () => {
return (
<div>
<h1>Welcome to Totally Ok Pizza Co.</h1>
<h2>Take a look at our menu and select your favorites!</h2>
<MenuItem />
</div>
)
}


export default Menu

In this example, Menu is the parent component while MenuItem is the child. It’s important to remember here that we can’t pass props up from the child. For example, if I attempted to add to Menu.js something like:

<h2>{item.name}</h2>

I’m going to get an error telling me ‘item’ is not defined because the parent can’t reach down to get that information from the child.

Whew! We did it. We created an object called pizzaData, named and defined its properties, and then passed those props to a React component to dynamically render our data. If you made it this far, you should feel proud!

Open Web Components

There are plenty of definitions out there for what constitutes the open web, but I enjoy this one from Mark Surman, Executive Director of the Mozilla Foundation: “An open web is a web by and for all its users, not select gatekeepers or governments.” Surman goes on to compare the open web to a global natural resource, like clean air or water, which requires care and protection if we want it to remain available for all long-term. This ideal is what we’re constantly working toward, and NEAR’s BOS(Blockchain Operating System) components are here to help us build a more open web.

If we take our pizza menu example and run with it, maybe a friend of ours is opening a specialty hamburger restaurant and they want help making their menu page. We show them our pizza menu and they say it’s exactly what they need. If we’d built this as a BOS component, they would be able to fork the Menu component, update the data to match their restaurant items, and then they could deploy a menu exactly like ours with very little extra work. Let’s take a look at what this might look like. I’m going to use the editor at Jutsu but don’t worry about building along with me right now. Just take a look at the code snippets and we’ll get to onboarding in our next article.

Just like in Next, I’ve created a MenuItem component (or widget — we seem to maddeningly use these interchangeably) and one for Menu. The MenuItem component defines what should be returned/rendered for each menu item.

const item = props.item;

return (
<div>
<div>
<img src={item.image} alt={item.alt} width="120" height="200"></img>
<h2>{item.name}</h2>
<p>{item.description}</p>
<h3>{item.price}</h3>
<span>{item.category}</span>
</div>
</div>
);

This is very similar to our MenuItem component with a few key differences. You’ll notice the component is not wrapped in a function statement, I start directly with the ‘return’ and the JSX. There is also no need to export this component to allow it to be used in other widgets. Once a widget is saved, it’s available for anyone to access via the NEAR Social Database. Now we need the Menu component.

const pizzaData = [
{
id: 1,
category: "meat",
name: "Pepperoni Pizzazz",
description: "A dazzling display of pepperoni majesty on a crispy crust",
price: "$15",
image:
"https://ipfs.io/ipfs/Qmar7EuchJancv5xbL7YPWByaxek8PBCBS467Q4s4oRDxg?filename=pepperoni.jpg",
alt: "pepperoni pizza",
},
{
id: 2,
category: "meat",
name: "Proud Pineapple",
description:
"Pineapple definitely goes on pizza. It's ok to disagree, you're allowed to be wrong",
price: "$16",
image:
"https://ipfs.io/ipfs/QmbMbWf7k9QrjN6H6uJEwLEzHSU3mEQehBsCpsWMPYmgfk?filename=pineapple.jpg",
alt: "pineapple pizza",
},
{
id: 3,
category: "vegetarian",
name: "Very Veggie",
description: "A collection of fresh veggies fit for a rabbit",
price: "$18",
image:
"https://ipfs.io/ipfs/QmaXRPUt1pfAPrUjzrPUVVPqk1X1csxyK8LHPBVc2tEdDk?filename=veggie.jpg",
alt: "vegetable pizza",
},
];

return (
<div>
<h1>Welcome to Totally Ok Pizza Co.</h1>
<h2>Take a look at our menu and select your favorites!</h2>
<div>
{pizzaData.map((item) => (
<div key={item.id}>
<Widget src="dawnkelly.near/widget/MenuItem" props={{ item }} />
</div>
))}
</div>
</div>
);

There are more differences to note here. Because our data consists of only three items, I’ve added them directly to the component for simplicity. All BOS components can natively communicate with NEAR’s SocialDB smart contract. You can use Social.set to commit a data object to SocialDB which can then be retrieved by any component using Social.get. We will do more with data in a future session but you can learn more about SocialDB here if you’re just too excited to wait. I also had to change how I handled images. You’ll notice I’m now using IPFS CID gateway urls rather than local or hosted files. The other thing that changed is where the map method is happening. We’re now saying “for each item in pizzaData, render an instance of MenuItem” and then use the props we name in MenuItem to dynamically render the correct Menu content to the browser.

The thing that really makes this special? All of the code needed to use the MenuItem component is saved to SocialDB and available to anyone on-chain. This creates a “Lego” type system of components that can be forked, customized, and combined in new ways to build and ship applications extremely quickly. Anyone who wants to render a menu of items, using the same group of properties, can use this component exactly as is. They can easily embed it in their Menu by simply adding the map method div to their application:

<div>
{pizzaData.map((item) => (
<div key={item.id}>
<Widget src="dawnkelly.near/widget/MenuItem" props={{ item }} />
</div>
))}
</div>

All that’s left is to update the data object to match our friend’s hamburgers and they have a menu up and running!

As you can see, there are only a few minor differences in creating basic BOS components vs React via NextJS. If you’re already working with React components, it might be fun to try and recreate your favorite components on Jutsu. You can use the online IDE to create and preview components without the need to log-in. You just won’t be able to save and share your components without a NEAR log-in. Our team is putting the finishing touches on a super easy way to establish a NEAR account if you don’t already have one. Hopefully, I can tell you all about it in our next article! Next time we’ll take things a step or two further and talk about destructuring and the spread operator. Don’t forget to practice!

--

--

Dawn Kelly

Blockchain builder and developer advocate. Chaotic good