Would You React ? - Build a Video App

Introduction

What is React?

React is a popular JavaScript frontend library open-sourced by Facebook. It allows you to create and re-use UI elements. React was born out of the need to solve the problem of the browser DOM being slow. It's famous and mostly used for a multitude of reasons.

Why use React?

Reusable components - React is component-based meaning that components are the building blocks of a React UI. A component describes how a smaller section of the UI looks like and is reusable. Complex applications can be built by nesting components within other components.

SPA - Another important thing about React is that it’s a Single Page Application (SPA). This means React doesn’t fetch a completely new web page when the user has to be shown a different view, it just re-writes the current web page with any new data fetched from the backend server.

Fast rendering with virtual DOM - Updating DOM is usually the bottleneck when it comes to the web performance. React uses virtual DOM; a DOM kept in memory. Any view changes are first reflected to virtual DOM, then the previous and current state of the virtual DOM is compared and only necessary and minimum changes are applied to DOM. This is the main reason behind React’s high performance.

Primary goals of this Article -

  • Understand how React renders HTML to UI.
  • Understand how to use JSX.
  • Understand React components, states, props and Lifecycle methods.
  • Create a React application (videos) from scratch.

Getting Started -

First, go to Terminal, and type -

npx create-react-app videos

This instruction creates a template of React application with name videos
To run your app on localhost:3000 in your browser, in your terminal type-

cd videos
npm start

This is how it will look like in Browser-

Cleanup -

Open src folder and delete the following files - App.test.js, logo.svg, setupTests.js
Delete everything in App.js and Index.js file.

Now that we have setup project and cleaned up unnecessary files, we can proceed to understand React.

In Index.js file, place following content-

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

ReactDOM.render(<App />, document.querySelector('#root'));

Lines 1 and 2: Importing the react and react-dom libraries. The react module is used to write HTML code within JavaScript (JSX) and react-dom is used to execute the render function that will display the contents onto the page.
Line 3: Importing App Component.
Line 4: Render App in a container which has an id of root.

The ReactDOM.render method-
What this method does is plugs in the App component to Browser's DOM. First parameter it takes is the React component to render and the second magic parameter is how we specify where in the public/index.html file we need to plug the component into. You’ll find a <div> element with id, root in public/index.html. This <div> element is the React container node. When the render() function is first called, the whole of the container node is replaced with App component.

Now we will be writing our App component (go to App.js file), But before that let's understand the basics -

JSX - React can support statements using JSX (JavaScript XML) which allows to use HTML like statements for creating UI elements (components) within JavaScript. You’ll find the JSX notation much easier to use as it’s very similar to how we write HTML.

Components - As said before, React is component based, Components are the building blocks in React and group of elements make up a component. Usually there’ll be a component each to define how the navigation bar looks, the content tab looks, login form looks etc. This also helps to wrap both the visual (elements) and logical (functions) aspects of a UI section together.

Breaking down our project into Components -

There will be 4 components in the Application.

  1. Searchbar (on Top)
  2. VideoDetail (on Left)
  3. VideoList (on Right)
  4. VideoItem (Items of VideoList)

Functional Components -
The simplest way to define a component is to write a JavaScript function.
in app.js -

import React from 'react';

function App(props) {
    return ();
}

This function is a valid React component because it accepts a single “props” object argument with data and returns the elements to be rendered when the component is rendered. We call such components “functional components” because they are literally JavaScript functions.

Class Based Components -
When creating a React component, the component's name must start with an upper case letter. The component has to include the extends React.Component statement, this statement creates an inheritance to React.Component, and gives your component access to React.Component's functions. A React component must at least have the render() function. The render() function returns the elements to be rendered when the component is rendered.

To render a component "Component", use the <Component /> tag.

For our App Component (App.js)
This is equivalent to the above functional component.

import React from 'react';

class App extends React.Component {
  render() {
    return ();
  }
}

Managing State in Class Components -
Data related to a particular component can be stored as its "state". State of a component can only be changed from that particular component only. All the state variables go inside a class variable, state, as key-value pairs.
React re-renders the UI whenever state changes.

Modifying the state-

  1. Do not Modify State Directly, as this will not re-render a component.
  2. Instead use setState(). when setState() is called, React knows the state has changed, and calls the render() method again to learn what should be on the screen. For example,
state = {selectedVideo: null}

//Wrong
this.state.selectedVideo = 'Something'

//Correct
this.setState({ selectedVideo: 'Something' })

Within the JSX notation, we can also plugin regular JavaScript expressions by wrapping them in braces ("{}").
For example -

<h1>{ 2 + 5 * 8 }</h1>

<p> Current Selected Video is : {this.state.selectedVideo} </p>

Please note that in early days, state could only be used in class components, not in functional components. That’s why functional components were also known as stateless components.
However, after the introduction of React Hooks, state can now be used both in class and functional components.
In this project we are not using React Hooks, therefore we will be using class components if it requires a state variable otherwise we use simple function component.

Props to inherit Properties -
Suppose that user has selected some Video which we store in this.state.SelectedVideo state variable. To Display that video in our VideoDetail component, we have to pass the information of selected video to VideoDetail component. Props or properties allow us to pass data from the parent components to the child components. We can pass "props" value to an individual component by passing it similar to how we do for an HTML attribute.

<VideoDetail video={this.state.selectedVideo} />

video is a defined prop here and contains selectedVideo data. Then we can pass data with props like we’re giving an argument to a function:

const VideoDetail = (props) => {
   // code
}

And finally, we use dot notation to access the prop data and utilise it as `props.video'

In Class Components, we can access properties as this.props.video

Note that the elements of JSX are just JavaScript objects. This means that a JSX element’s props and children can be anything that you could place in a JavaScript variable — they can be strings, state variables, other components, or even functions. You will see in project, how we can pass different things as props to components.

Lifecycle Methods-
The lifecycle of an instance of a React component comprises three phases.
Mounting - when it gets created and inserted into the DOM.
Updating - when it gets updated or re-rendered due to a change in its state values.
Unmounting - when it gets removed from the DOM.
Each of these lifecycle phases involves executing a set of lifecycle methods.

1.componentDidMount() - is called immediately after the component gets mounted and can be used to perform initializations which’ll require the DOM nodes to be in place. here we can perform tasks like fetching data from an API.

2.componentDidUpdate() - A component will be updated/re-rendered whenever any of its props or state values changes. componentDidUpdate() is called immediately after a component is updated. It can be used to implement any logic to execute after re-rendering.

There are other lifecycle methods which I will not be explaining in this article. We will be only using componentDidMount() in this project.

ok!!

Now that we’ve gotten this out of the way, it’s finally time to get our feet wet!

Important - We will use semantic ui for styling components. (Semantic is a development framework that helps create beautiful, responsive layouts using human-friendly HTML.) For that, Add this line inside head in public/index.html -


<link rel = 'stylesheet' href = "https://cdnjs.cloudflare.com/ajax/libs/semanticui/2.4.1/semantic.min.css"
integrity = "sha512-8bHTC73gkZ7rZ7vpqUQThUDhqcNFyYi2xgDgPDHc+GXVGHXq+xPjynxIopALmOPqzo9JZj0k6OqqewdGO3EsrQ==" crossorigin = "anonymous" />

Project Folder Structure -

Also, please note that this article's goal is to primarily focus on React concepts. So please feel free to ignore irrelevant topics.

index.js -`

import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App';

ReactDOM.render(<App />, document.querySelector('#root'));

apis/youtube.js

import axios from 'axios';

// create your youtube api key and place it here
const KEY = YOUR_API_KEY;

// setting up base instance in which you can define a URL and
// any other configuration elements.
// and exporting as default.

export default axios.create({
    baseURL: 'https://www.googleapis.com/youtube/v3',
    params: {
        part: 'snippet',
        maxResults: 5,
        key: KEY
    }
});

// we can import this instance from other files and no longer need to write 
// whole URL everytime we call API

VideoItem.js

import './VideoItem.css';
import React from 'react';

// takes props video object and onVideoSelect function
// we call onVideoSelect when user clicks the video

// What does a VideoItem Component contains?
// yepp, Video Thumbnail and Video title

const VideoItem = ({ video, onVideoSelect }) => {
    return (
        <div onClick={() => onVideoSelect(video)} className="item video-item">
            <img alt={video.snippet.title} className="ui image" src={video.snippet.thumbnails.medium.url} />
            <div className="content">
                <div className="header">{video.snippet.title}</div>
            </div>
        </div>
    );
}

export default VideoItem;

VideoItem.css

.video-item{
    display: flex !important;
    align-items: center !important;
    cursor: pointer;
}

.video-item.item img{
    max-width: 180px;
}

VideoList.js

import React from 'react';
import VideoItem from './VideoItem';

// takes videos (video array) and onVideoSelect function
// What does a VideoList contain?
// yepp, List of Video (specifically VideoItems)
// So we iterate over videos array and make a VideoItem for each
// Note We are passing video and OnVideoSelect as props to VideoItem

const VideoList = ({ videos, onVideoSelect }) => {

    const renderedList = videos.map((video) => {
        return <VideoItem key={video.id.videoId} onVideoSelect={onVideoSelect} video={video} />;
    })

    return <div className="ui relaxed divided list">{renderedList}</div>;

}

export default VideoList;

VideoDetail.js

import React from 'react';

// videoDetail takes the selectedVideo and displays its info.

const VideoDetail = ({ video }) => {
    if (!video) {
        return <div>Loading...</div>;
    }

    //This url is for fetching selectedVideo
    const videoSrc = `https://www.youtube.com/embed/${video.id.videoId}`;

    return (
        <div>
            <div className="ui embed">
                <iframe title="video player" src={videoSrc} />
            </div>
            <div className="ui segment">
                <h4 className="ui header">{video.snippet.title}</h4>
                <p>{video.snippet.description}</p>
            </div>
        </div>
    );
}

export default VideoDetail;

SearchBar.js

import React from 'react';

// state variable "term" stores what user types in searchBar

class SearchBar extends React.Component {
    state = { term: '' };

    // this sets the "term" to what user types in. (in sync)
    onInputChange = (e) => {
        this.setState({ term: e.target.value });
    }

    // it is called when user submits the "term"
    // which in turn calls the onTermSubmit() function passed as its prop
    onSearchBarSubmit = (e) => {
        e.preventDefault();
        this.props.onTermSubmit(this.state.term);
    }

    render() {
        return (
            <div className="ui segment search-bar" style={{ marginTop: '20px' }}>
                <form onSubmit={this.onSearchBarSubmit} className="ui form">
                    <div className="field">
                        <label>Video Search</label>
                        <input
                            style={{ backgroundColor: 'whitesmoke' }}
                            type="text" value={this.state.term}
                            onChange={this.onInputChange}
                        />
                    </div>
                </form>
            </div>
        );
    }
}

export default SearchBar;

App.js

import React from 'react';
import SearchBar from './SearchBar';
import VideoList from './VideoList';
import youtube from '../apis/youtube';
import VideoDetail from './VideoDetail';

class App extends React.Component {
    state = { videos: [], selectedVideo: null };
    // videos - array of videos based on term that user passed in searchbar (initally empty)
    // selectedVideo - video selected to display on left 


    // this lifecycle method is called when App component gets mounted 
    componentDidMount() {
        this.onTermSubmit('dev.to');
    }
    // Note that here 'dev.to' is initial term for which videos will be searched
    // It is random



    // This function is the one that accepts the term and fetches videos
    // and set "videos" state variable to fetched videos and
    // selectedVideo to the first video of videos
    onTermSubmit = async (term) => {
        const response = await youtube.get('/search', {
            params: {
                q: term
            }
        });
        this.setState({ videos: response.data.items, selectedVideo: response.data.items[0] });
    }

    onVideoSelect = (video) => {
        this.setState({ selectedVideo: video });
    };

    render() {
        return (
            <div className="ui container" style={{ backgroundColor: 'whitesmoke', padding: '40px' }}>
                <SearchBar onTermSubmit={this.onTermSubmit} />
                <div className="ui grid">
                    <div className="ui row">
                        <div className="eleven wide column">
                            <VideoDetail video={this.state.selectedVideo} />
                        </div>
                        <div className="five wide column">
                            <VideoList onVideoSelect={this.onVideoSelect} videos={this.state.videos} />
                        </div>
                    </div>
                </div>
            </div>
        );
    }

}

export default App;

Conclusion

In this Article, we learned basic concepts of ReactJS and how these concepts are applied in a Real Project. Now that you have basic understanding of React, you can move to more advanced topics such as Hooks, Redux etc.

Thanks for Reading

This is my first ever post on Dev. I hope you enjoy this and wasn't overwhelming. If you liked the article, please ❤️. Happy coding 😊.

42