You probably must have heard about React more often these days. React is the most popular JavaScript Framework through which you can build powerful websites easily. Today, we'll be looking at some basics of React and we'll also build a simple mini calendar as we go!
Here's what it will look like:
Here's the source code.
Part 1: Prerequisites
You should have some familiarity with HTML and JavaScript as well as programming functions like functions, objects, arrays etc. If you know some basics of React, It will be good for you. If not, I will recommend you this workshop. But don't worry, you should be able to follow along regardless. If you're having trouble, feel free to ask me or anyone in the Hack Club Slack!
Part 2: Setup
So far, we've been using repl.it for most of our workshops. But today, I want to introduce you to another online code editor, CodeSandbox. For making any React projects, CodeSandbox is the best one out there.
To get started, go to this starter code. Press ctrl+s
/ cmd+s
and it will automatically fork it for you. Now, we have everything set up so let's get started!
Part 3: Building the project
1) File Structure and Basics
Let's first have a look at our project's file structure.
First, there are 2 main directories and a package.json file. We'll ignore the package.json file for now and let's have a look at the 2 directories, namely, public/
and src/
.
Usually, the public/
directory contains an HTML file and all your assets. We won't be touching the public/
directory during the whole workshop, not even the HTML file!
Next is the src/
directory which contains all your JavaScript files and your CSS files. We have an index.js
file, which basically renders our React code. Next is the App.js
file. We can start writing our React code from here itself, but it is a convention to split our code into small components and render them together in our App.js
file.
This is what our App.js
file look right now. Let's understand it line by line.
import React from "react";
import "./styles.css";
export default function App() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
</div>
);
}
At line 1, we import React into our file. Similarly, at line 2, we import the CSS file. We also need to export our App
component so that the index.js
file can have an access to it and render it. Therefore, we write our function beginning with export default
.
Also, this is a React component, so the function will always return jsx code.
What is jsx? All the code from line 6 to 9 is known as jsx. It is pretty much similar to HTML but there are few differences which we'll see as we go along.
You'll see that instead of using class
in our <div>
tag, we are using className
, this is one of the difference between jsx and HTML. Whenever we add class to our element in React, we'll use className
instead of class
.
This is pretty much about the App.js
file as well as some React.
Now, have a look at the components/
directory, it contains a components.css
file which is prewritten for you, as our main focus today will be on React. In this directory, we'll write and store all our children components. Then we'll export them using export default
and import them in our App.js
file and therefore it will be rendered.
Navigate, to App.js
file and remove the heading tags from the code.
Let's now start writing some code!
2) Writing The Components
1) CalendarUI Component
Let's start writing our very first component! Navigate to the components/
directory, hover over the directory name, and you'll see few options. If you click on the 3rd option which says 'New File', it will create a new file inside the components/
directory. It will ask you the filename. Let's name the file as CalendarUI.js
.
Note: For naming filenames in React, we use the TitleCase
convention.
Next, open the file which you just created and let's write our first React code.
We'll first import React
and components.css
in this manner:
import React from 'react';
import './components.css';
Note: The ./
on line 2 means that the file which we are importing is in the same directory.
Next, we'll create a functional component. You can create it the normal way or by following the ES6 syntax. Here's how you'll do it either way.
function CalendarUI() {
return()
}
OR
const CalendarUI = () => {
return()
}
Use any syntax you like or feel that it is suitable/easier for you to understand.
Now we will return jsx code in our functional component. One remarkable thing to keep in mind is that we can't return more than 1 parent elements in our code. So, we'll always need to create a main parent <div>
tag and then write all the code inside of that.
This is wrong:
return(
<h1>Hello world</h1>
<h1>Lol</h1>
<h1>Hi!!</h1>
)
This is the correct way:
return(
<div>
<h1>Hello world</h1>
<h1>Lol</h1>
<h1>Hi!!</h1>
</div>
// Don't write anything outside the parent element.
)
Now let's write the following jsx code (inside the return
parenthesis).
<div className="container">
<div className="main">
<p className="month"></p>
<p className="day"></p>
<p className="date"></p>
<p className="year"></p>
</div>
</div>
We won't see anything in our preview now, because our <p>
tags are empty. By looking at the className
you might have understood what will come there. Let's hardcode today's date in it and let's check our preview window!
Wait what? Nothing on the preview window? It's because we haven't followed our 5th and the 6th step yet!
It is a common mistake to forget this step while writing React, so if you ever feel your code isn't working fine, check your imports and exports first!
At the very end of our file, we'll export the component.
export default CalendarUI;
Your code so far:
import React from 'react';
import './components.css';
const CalendarUI = () => {
return(
<div className="container">
<div className="main">
<p className="month">October</p>
<p className="day">Sunday</p>
<p className="date">18</p>
<p className="year">2020</p>
</div>
</div>
)
}
export default CalendarUI;
We can also export it without the default
keyword but for the scope of this workshop, we'll use the default
keyword. Now we also need to import it somewhere so that it is rendered. Can you guess where will we import it? Yes! It's the App.js
file.
Difference between export
and export default
.
Navigate to your App.js
file and let's import it.
import React from "react";
import "./styles.css";
// Below all your imports add a new line to import our new component.
import CalendarUI from "./components/CalendarUI";
We'll first write the name of the component we want to import and then we specify its filepath which is, in our case, ./components/CalendarUI
.
Then, we treat our component just as an HTML tag and we'll write it in the return()
of our App
component.
return (
<div className="App">
<CalendarUI />
</div>
);
Now if you look at the preview, you'll be amazed to see that we have correctly written our React code!
But, we have hardcoded our date, right? Let's fix that now.
2) Fixing The Hardcode
In our CalendarUI component, we'll now use a hook called as useState()
. It is an efficient way of managing our data by storing them in states and rendering it in our component. (You can do many more things with the state).
First, we'll import it from react
. So we'll change the first line as:
import React, { useState } from 'react';
Note: The useState()
was not exported as default
. That is why, we import it surrounded by curly braces.
Now inside our component, just above the return
statement, we'll create the state.
const [today, setToday] = useState(new Date());
Explanation: we define the 2 variables using the array destructuring syntax. The first variable (today
) stores the default state and the second variable (setToday
) helps in changing the value of the default state.
Next, we call the useState()
and it takes in a value which will be the default state. So, we stored the today's date.
Note: It is also a convention to use the word set
for the 2 variable which basically helps in changing the state.
Learn more about React useState
.
Now, we can extract the year, month etc from our state and store them in other variables. We'll write these variable below the useState()
and above the return()
.
const year = today.getFullYear();
const month = today.toLocaleString("default", { month: "long" });
const day = today.toLocaleString("default", { weekday: "long" });
const date = today.getDate();
Explanation: the getFullYear()
method will give us the current year and the getDate()
will also give us the current date.
But for month and day, if we use getMonth()
and getDay()
it returns the value in numbers. So if we want to get them in words, we need to use something called toLocaleString()
which takes in our locale as the first parameter and an object with the value we want to return with its type. So, we put in the default
locale and then we return the month
and the weekday
as long
.
Note: This is nothing React specific but it is how we would have done in JavaScript.
Learn more about toLocaleString()
.
Now, instead of hardcoding our values inside of our <p>
tag, we can pass these variables inside the <p>
tag.
Here comes the best thing about React.
Remember how we used to pass JavaScript variables inside HTML?
This is one of the way of doing it in plain JavaScript. But surprisingly, React can do this job better! Here's how:
<div className="container">
<div className="main">
<p className="month">{month}</p>
<p className="day">{day}</p>
<p className="date">{date}</p>
<p className="year">{year}</p>
</div>
</div>
We just pass the variable name in curly braces and we are done! Now if we look at the preview, we see the same thing but this time, we didn't hardcode it.
Our code so far:
import React, { useState } from "react";
import "./components.css";
const CalendarUI = () => {
const [today, setToday] = useState(new Date());
const year = today.getFullYear();
const month = today.toLocaleString("default", { month: "long" });
const day = today.toLocaleString("default", { weekday: "long" });
const date = today.getDate();
return (
<div className="container">
<div className="main">
<p className="month">{month}</p>
<p className="day">{day}</p>
<p className="date">{date}</p>
<p className="year">{year}</p>
</div>
</div>
);
};
export default CalendarUI;
We have successfully built a basic UI using React. Now let's learn how to manipulate states in React. If you saw the demo at the beginning of the workshop, we were able to navigate back and forth dates. This was done using state manipulation. If the state gets changed, the components are re-rendered and thereby show the new state. Let's start implementing this.
3) ChangeDate Component
In our components file, let's create another component named ChangeDate.js
. Try to fill out that file with the basic boilerplate code by referring the 5 steps of writing React.
You should have something like this in your ChangeDate.js
file.
import React from "react";
import './components.css'
const ChangeDate = () => {
return (
<div></div>
);
};
export default ChangeDate;
Also, give the <div>
tags a className
of buttons
.
Now states are limited to that component itself. So we can't access our today
state which is in CalendarUI
component in our ChangeDate
component.
So we'll need to pass that state in the form of props
to our ChangeDate
component. But for that, ChangeDate
component needs to be the child component of CalendarUI
. Confused? You'll understand it better once you write the code.
So we will import our ChangeDate
component inside our CalendarUI
component and then we'll render it there.
import React, { useState } from "react";
import "./components.css";
import ChangeDate from "./ChangeDate.js"; // IMPORT THE COMPONENT
const CalendarUI = () => {
const [today, setToday] = useState(new Date());
const year = today.getFullYear();
const month = today.toLocaleString("default", { month: "long" });
const day = today.toLocaleString("default", { weekday: "long" });
const date = today.getDate();
return (
<div className="container">
<div className="main">
<p className="month">{month}</p>
<p className="day">{day}</p>
<p className="date">{date}</p>
<p className="year">{year}</p>
</div>
</div>
<ChangeDate /> {/* RENDER THE COMPONENT */}
);
};
But now, the browser will be badly yelling at you!!
That is because we are rendering the <ChangeDate />
outside the parent element. But here, we can't take it in because it will become a flex child (the container
className is set to display: flex
) and will be displayed weirdly on the browser.
Here comes something called fragments
. If we add an empty tag as a parent element, we won't get errors anymore! Fragments let you group a list of children without adding extra nodes to the DOM.
If you are confused, here's how we'll do it.
return (
<> {/* Fragments opening tag */}
<div className="container">
<div className="main">
<p className="month">{month}</p>
<p className="day">{day}</p>
<p className="date">{date}</p>
<p className="year">{year}</p>
</div>
</div>
<ChangeDate />
</> {/* Fragments closing tag */}
);
Now, as the component has a parent element, we won't get the errors anymore!
Learn more about React fragments.
Let's see how to pass our state as props
to <ChangeDate />
.
We'll first name the prop
and then pass a value to the prop
.
<ChangeDate state={today} setter={setToday} />
Here, we name our first prop as state
and then pass the value as today
. Similarly, we name the second prop as setter
and then pass it the setToday
function.
Learn more about passing states as props to children.
And now it is possible to manipulate the state from the ChangeDate
component as it has access to those values. Let's move back to ChangeDate.js
as we will also need to receive those props. This is done by adding their names as parameters in curly braces to our functional component.
const ChangeDate = ({state, setter}) => {
return (
<div className="buttons"></div>
);
};
In this way, we have received our props from the parent component and now we can use it in our component. Now we'll add 3 buttons to navigate back and forth as well as reset back to today.
We are going to use some SVGs taken from Heroicons. So I recommend you to copy the below code inside the buttons
div to save some time.
import React from "react";
const ChangeDate = ({state, setter}) => {
return (
<div className="buttons">
<button className="prev">
<svg
xmlns="http://www.w3.org/2000/svg"
width="32px"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor">
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M15 19l-7-7 7-7"/>
</svg>
</button>
<button className="reset">
TODAY
</button>
<button className="next">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
width="32px"
viewBox="0 0 24 24"
stroke="currentColor">
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M9 5l7 7-7 7"/>
</svg>
</button>
</div>
);
};
export default ChangeDate;
We have basically taken 2 SVGs from Heroicons and inserted them to our button.
NOTE: We can remove the import
for styles from this file as it is a children of CalendarUI
so it will eventually get the styles.
This is what you'll see in the preview window now.
We have our UI totally set up. Now we'll implement 3 functions to go back, forth and also to get back to the current date.
Inside the ChangeDate
component and just above the return statement, let's create a function named previousDate
. Now we'll need to subtract 1 from the current date to get the previous date. Here's how we'll accomplish this task.
function previousDate() {
state.setDate(state.getDate() - 1);
setter(new Date(state));
}
Explanation: We subtract the today
state's date by 1, by using the setter
function (which is setToday()
in diguise), we pass a new Date
with a value of state
(which is -1 at that moment). Our date will change to the current date stored in today - 1
.
Learn more about adding dates in JavaScript.
Challenge: Create a similar function nextDate
which will set the date to today + 1
.
And lastly, we'll create a resetDate
function which will simply reset the date back to its original value.
function resetDate() {
setter(new Date());
}
Here's the code for all our 3 functions:
function previousDate() {
state.setDate(state.getDate() - 1);
setter(new Date(state));
}
function nextDate() {
state.setDate(state.getDate() + 1);
setter(new Date(state));
}
function resetDate() {
setter(new Date());
}
NOTE: We are using the name state
instead of using the actual name of our state which is today
. This is because, we previously passed the today
state with the name of state
to this component. You can change it to any name you like.
Finally, for our buttons to work, we need to link those functions to the button. So to do that, we'll add an onClick
attribute to the button exactly as we did in HTML by adding onclick
to our buttons. But there are a few differences. Let's take a look.
-
The
onclick
is lowercase in HTML but camelcase (onClick
) in React. -
We call the function in quotations in
onclick
in HTML. In React, we need to pass the name of the function in curly braces but not call it.
Here's a better example:
HTML:
<button onclick="functionName()">BUTTON</button>
React:
<button onClick={functionName}>BUTTON</button>
Now that you know how to implement onClick
in React, try to do this on your own!
Challenge: Pass the onClick
attribute to the buttons with appropriate functions.
Here's the full final code.
import React from "react";
const ChangeDate = ({ state, setter }) => {
function previousDate() {
state.setDate(state.getDate() - 1);
setter(new Date(state));
}
function nextDate() {
state.setDate(state.getDate() + 1);
setter(new Date(state));
}
function resetDate() {
setter(new Date());
}
return (
<div className="buttons">
<button onClick={previousDate} className="prev">
<svg
xmlns="http://www.w3.org/2000/svg"
width="32px"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M15 19l-7-7 7-7"
/>
</svg>
</button>
<button onClick={resetDate} className="reset">
TODAY
</button>
<button onClick={nextDate} className="next">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
width="32px"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M9 5l7 7-7 7"
/>
</svg>
</button>
</div>
);
};
export default ChangeDate;
Yay! I'm happy to say that this is the end of our workshop! Yes, we have completed building our React Calendar!
Part 4: The End
Make sure you create an account on CodeSandbox to save this wonderful piece of creation or you'll loose it 😧.
Now it is up to you! Do crazy things with this project!
Here are some useful resources for you!
Here are some tasks for you!
-
Try to add the current time below the calendar.
-
Make the calendar look like a stack of cards.
Check this Example to get an idea. -
Play around with the CSS! (changing the display, fonts, animations etc) If you want help in doing it, check this workshop!
-
Try to make it isometric using CSS 3d Transforms.
Check this Example to get an idea. -
Try to add options for displaying the calendar in a month view and week view!
-
Even the
Date
object has so many features that you can play around with! -
Finally, React is a whole different universe, play around with your newly learnt skills!
Check out what other Hack Clubbers built!
Now that you have finished building it, you should share your beautiful creation with other people! (I can't wait to see you ship this!)
You probably know the best ways to get in touch with your friends and family, but if you want to share your project with the worldwide Hack Club community there is no better place to do that than on Slack.
- In a new tab, open and follow these directions to signup for our Slack.
- Then, post the link to the
#ship
channel to share it with everyone and also ping me!
PS. I'm @fayd
on slack!