ReactJs: YouTube Instant search working with API

This tutorial will explain how to achieve to get YouTube instant search with API using ReactJs. You can find step by step tutorial to get the output. Demo and Download are available.

DownloadDemoGitHub

Before going to the tutorial, we have to setup the reactJs project. Follow the link to setup the reactjs project.

Folder Structure

Once the setup done using the above link you will see the below folder structure.

After creation, your project should look like this:

my-app
├── README.md
├── node_modules
├── package.json
├── .gitignore
├── public
│   └── favicon.ico
│   └── index.html
│   └── manifest.json
└── src
    └── App.css
    └── App.js
    └── App.test.js
    └── index.css
    └── index.js
    └── logo.svg
    └── registerServiceWorker.js

Now we have to create the below listed folders inside the “src” folder.

  • components
  • css
  • fonts
  • services

Now create the below listed js files inside “components” folder

  • App.js
  • ListFilteredVideos.js
  • NextPrevious.js
  • Search.js
  • VideoListLayout.js

Now download the bootstrap dependency files from Bootstrap website and place the files to their respected folders.

Now create the below js file inside “services” folder

  • YouTubeGetData.js

Delete the below files from the “src” folder

  • App.js
  • App.css
  • index.css
  • logo.svg

Once the above steps are done, you will see the below folder structure

my-app
├── README.md
├── node_modules
├── package.json
├── .gitignore
├── public
│   └── favicon.ico
│   └── index.html
│   └── manifest.json
└── src
	└── components
	    └── App.js
	    └── ListFilteredVideos.js
	    └── NextPrevious.js
	    └── Search.js
	    └── VideoListLayout.js
	└── css
	    └── bootstrap.min.css
	└── fonts
	    └── glyphicons-halflings-regular.eot
	    └── glyphicons-halflings-regular.svg
	    └── glyphicons-halflings-regular.ttf
	    └── glyphicons-halflings-regular.woff
	    └── glyphicons-halflings-regular.woff2
	└── services
	    └── YouTubeGetData.js
    └── App.test.js
    └── index.js
    └── registerServiceWorker.js

Now, Let’s start writing the code.

Open the “index.js” from “src” folder and copy past the below code.

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

ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();

Open the “App.js” from “src/components” folder and copy past the below code.

import React from 'react';
import ListFilteredVideos from './ListFilteredVideos.js';
import Search from './Search.js';
import NextPrevious from './NextPrevious.js';
import {youtubeApiServiceCall} from './../services/YouTubeGetData.js';
import '../css/bootstrap.min.css';

export default class App extends React.Component {
	constructor(props) {
		super(props);

		this.state = {
		  posts: [],
	      filterText: 'HTML Tutorials',
	      nextPageToken:'',
	      prevPageToken:'',
	      pageToken:''
	    }
	};
	tokenUpdate(token) {
		youtubeApiServiceCall(this.state.filterText, token).then((obj) => {
			this.setState({
				'posts':obj.posts,
				'nextPageToken':obj.nextPageToken,
				'prevPageToken':obj.prevPageToken
			});
		});
	};
	filterUpdate(value) {
		this.setState({
			filterText: value
		});
		youtubeApiServiceCall(this.state.filterText).then((obj) => {
			this.setState({
				'posts':obj.posts,
				'nextPageToken':obj.nextPageToken,
				'prevPageToken':obj.prevPageToken
			});
		});
	};
	componentDidMount() {
		youtubeApiServiceCall(this.state.filterText).then((obj) => {
			this.setState({
				'posts':obj.posts,
				'nextPageToken':obj.nextPageToken,
				'prevPageToken':obj.prevPageToken
			});
		});
	}
	render() {
		return (<div>
			<Search filterVal={this.state.filterText} filterUpdate={this.filterUpdate.bind(this)}></Search>
			<NextPrevious nextPageToken={this.state.nextPageToken} prevPageToken={this.state.prevPageToken} tokenUpdate={this.tokenUpdate.bind(this)}></NextPrevious>
			<ListFilteredVideos posts={this.state.posts}></ListFilteredVideos>
		</div>);
	};
};

Open the “ListFilteredVideos.js” from “src/components” folder and copy past the below code.

import React from 'react';
import VideoListLayout from './VideoListLayout.js';

export default class ListFilteredVideos extends React.Component{
	render(){
		const {posts} = this.props;
	    return (<div className="panel-body">
			{posts.map((post, i) =>
				<VideoListLayout key={i} posts={post}> </VideoListLayout>
			)}
		</div>);
	};
};

Open the “NextPrevious.js” from “src/components” folder and copy past the below code.

import React from 'react';

export default class NextPrevious extends React.Component{
	render(){
		var divStyle = {
		  	textAlign: 'center'
		};
		const { nextPageToken, prevPageToken, tokenUpdate} = this.props;
	    return (
	    	<div style={divStyle}>
			    <div className="btn-group">
				    {prevPageToken &&
					  <button type="button" id="pageTokenPrev" className="btn btn-default" onClick={() => {
					   tokenUpdate(prevPageToken)
					  }}>Prev</button>
					}
					{nextPageToken &&
						<button type="button" id="pageTokenNext" className="btn btn-default" onClick={() => {
							tokenUpdate(nextPageToken)
						}}>Next</button>
					}
			    </div>
			</div>
		);
	};
};

Open the “Search.js” from “src/components” folder and copy past the below code.

import React from 'react';

export default class Search extends React.Component {
  render() {
    const { filterVal, filterUpdate} = this.props;
    return (
      <form>
        <input
          type='text'
          ref='filterInput'
          placeholder='Type to filter..'
          // binding the input value to state
          value={filterVal}
          onChange={() => {
           filterUpdate(this.refs.filterInput.value)
          }}
        />
      </form>
    )
  }
};

Open the “VideoListLayout.js” from “src/components” folder and copy past the below code.

import React from 'react';

export default class ListFilteredVideos extends React.Component{
	render(){
		const {posts} = this.props;
		const url = 'https://www.youtube.com/watch?v='+posts.id.videoId,
			  imgUrl = posts.snippet.thumbnails.default.url,
			  title = posts.snippet.title,
			  channelTitle = posts.snippet.channelTitle,
			  channelUrl = 'https://www.youtube.com/channel/'+posts.snippet.channelId;

	    return (<div className="col-sm-4 col-lg-4 col-md-4">
	    <div className="well well-sm media">
	        <a className="thumbnail pull-left" target="_block" href={url}><img alt={title} src={imgUrl} width="120" height="90" /></a>
	        <div className="media-body">
	            <a target="_block" href={url}>{title}</a>
	            <p>By <a target="_block" href={channelUrl}><span className="label label-info">{channelTitle}</span></a></p>
	        </div>
	    </div>
	</div>);
	};
};

Open the “YouTubeGetData.js” from “src/services” folder and copy past the below code.

export function youtubeApiServiceCall(filterText, pageToken){
	let pageTokenVal = '';
  if (pageToken) {
    pageTokenVal = "&pageToken="+pageToken;
  }

	const val = filterText;
	const url = "https://www.googleapis.com/youtube/v3/search?key=YOUTUBE_API_KEY&q="+val+"&type=video&part=snippet&maxResults=12"+pageTokenVal;

    return new Promise((resolve, reject) => {
    	fetch(url, {
		    method: 'get',
		    headers: {
		        'Accept': 'application/json'
		    }
		}).then(function(res) {
			return res.json();
		}).then(function (data) {
	        const posts = data.items.map(obj => obj);
	        const{nextPageToken,prevPageToken} = data;
	        const objects = {
	        	'posts':posts,
	        	'nextPageToken':nextPageToken,
	        	'prevPageToken':prevPageToken
	        };
	    	resolve(objects);
	    });
    });
};

Note: Replace “YOUTUBE_API_KEY” with your youtube API key

Alright… Every thing is done!!!

Now, Time to run the code and see the output

Open the terminal and cd to the project folder like below video

// To run the project
npm start
// To take a build
npm run build

W3TWEAKS
Latest posts by W3TWEAKS (see all)

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *