Lesson 12

Building the interface with React

2

This chapter will be quite centered around JavaScript and React. Even though it's not directly linked to the Solidity programming language, writing DApps isn't all about coding smart contracts, but also building the user interface around it!

Since this isn't really a React tutorial though, this part of the course will be a bit quicker and not explained in as much detail. In other words, don't feel too bad if you mostly just copy-paste the code in this chapter.

Start by downloading the following zip-file with all the image files for Tweether:

bgCombined Shape

Unzip it, and drag the icons and static folders to your Tweether project's client directory so that the final folder structure looks like this:

Working with components

To get an idea of how we work with components in React, we'll create a Center component. This is something we'll use on almost all our pages, simply to limit how wide the contents of the page should be.


This is how the <Center> component should work. Just imagine it without the ugly red line of course.

We start by creating a components folder in client, and in in, we add a new file called Layout.js. The component that we define inside the file should be very simple, and uses styled-jsx to generate the CSS:

client/components/Layout.js

Now we head back to pages/index.js, import the Center component, and use it as the root component instead of div in our render function:

client/pages/index.js

You'll probably barely notice the difference from before, but if you look closely, you'll see that the content of your index page is now limited to a certain width:


Your page won't have the ugly red box though.


Creating a page layout

If we think about it, most of our pages look pretty similar – they use the same font, background color and header for example. In a situation like that, it's usually a good idea to create a wrapper component, which is then used on every page to "set the tone".

In our project, we'll simply call this wrapper component Page, and define it in our existing Layout.js file. We'll import the Google font that we want to use (in this case, Lato) in the Head, then set some basic styles using CSS.

client/components/Layout.js

if we import this into our index page, and replace Center with Page, you'll notice the new background colour on your page.

client/pages/index.js


Adding the header

Let's move on to some more advanced components! As you might remember, this is what we want the header in our DApp to look like:

In this component, we'll want to import the SVG logo file that we downloaded earlier. To make this easy, we can use the Babel plugin babel-plugin-inline-react-svg.

To use it, we need to create a .babelrc file at the root of our project. This will override the default Babel configuration for your Next project, so we need to make sure that we first add @babel/env and next/babel as presets:

.babelrc

After this, make sure you restart the server using npm run dev so that the changes can take effect. Next, we create the Header.js component file in the components folder.

As you can see below, we can now easily import our logotype.svg as a LogoType component, and place it where we see fit. We've also taken the liberty to add some extra CSS that you'll need in an upcoming chapter, so make sure that you copy-paste all of it!

client/components/Header.js

Now we import the Header component into the Layout.js file, and add it to our Page component's render function. That way, it will show up on all pages that use Page as a wrapper component!

client/components/Layout.js
Voila!

Building the landing page

Next up, we're going to build our landing page design!


What we want our landing page to look like.


For this, we're going to delete most of the stuff we have in index.js, and replace it. Our buttons were just for demo purposes anyway, and we're going to integrate their functionality in some other places inside the app instead. Let's start by deleting everything inside the IndexPage component, so that we just have a plain page template:

client/pages/index.js

Then we fill our page with the following content:

client/pages/index.js


You should already be able to get a glimpse of the final product now!


The only thing missing from the page is a pretty signup button. For that, we'll create a new Button component that we can re-use in other places as well.

client/components/Button.js

Then we import the Button, as well as our MetaMask SVG logo, and place them right before our disclaimer text. We also add some padding to the left side of the button so that it encapsulates our MetaMask logo in a nice way.

client/pages/index.js


Great!


Signup modal

When we click the "Create your account" button, we want a modal with a registration form to appear. Since we'll be using modals in other parts of our app (when creating a tweet for example), it makes sense to create a reusable Modal component.

client/components/Modal.js

To try it out, we import the modal into our index page, and add this.toggleRegisterModal as an action to our button. The toggleRegisterModal-method simply toggles the value of the boolean state variable showRegisterModal in order to decide whether the Modal component should be rendered or not.

client/pages/index.js

With this, you should be able to click the button to show the modal, and click outside to dismiss it.


The only thing missing now is the registration form! We'll create a new file for that containing both an Input component and a RegistrationForm component:

client/components/RegistrationForm.js

The actual logic for the this.createUser method will be implemented in the next chapter. For now we focus only on presentation.

As usual, we import the component into the index page, and render it inside the Modal component:

client/pages/index.js


Here's the final result!


Obviously, our form isn't working yet, since there's no communication with the Ethereum blockchain, but now the web app is looking a lot fresher!

Comments

Phaedrus Raznikov

The RegistrationForm also never imports React, definite bug

Phaedrus Raznikov

The RegistrationForm component pulls an onClose prop but never uses it. Is this a typo?

Phaedrus Raznikov

Getting "Error: Cannot find module '@babel/preset-env'" when trying to configure the .babelrc file

Marc-Antoine Rocca-Serra Beaudet

Hello, I have some errors here, "Cannot read property 'showRegisterModal' of null" and then "Maximum call stack size exceeded"

Tristan Edwards

@marc-antoine-rocca-serra-beau: That sounds weird. Did you add the initial state to your component (line 10-13)?

Marc-Antoine Rocca-Serra Beaudet

Hello again,

Marc-Antoine Rocca-Serra Beaudet

I tried over and over and nothing worked

Marc-Antoine Rocca-Serra Beaudet

Today it's working fine, feel free to delete. And sorry for the multiple messages I'm on mobile right now ^^

profile/avatar/default
Zhuimengshaonian04

in ./client/pages/index.js Module build failed: TypeError: Cannot read property 'bindings' of null

profile/avatar/default
Zhuimengshaonian04

in ./client/pages/index.js Module build failed: TypeError: Cannot read property 'bindings' of null