React integration is nothing but converting a web component to a React component by using JSX, Redux, and other React methods.
Let's see one practical example of React integration with another API.
This app will help you to integrate the Facebook API and you will have access to your profile picture and however many friends you have in your friends list. You will also see how many likes, comments, and posts there are in a respective friend's list.
To start with, you have to install the Node.js server and add the npm package in your system.
If you don't know how to install Node.js then please see the following instructions.
First, we have to download and install Node.js version 0.12.10, if we have not installed it on the system. We can download Node.js from http://nodejs.org and it includes the npm package manager.
Once the setup is done, we can check whether Node.js was set up properly or not. Open the command prompt and run the following command:
node -v
OR
node --version
This will return the Node.js installed version, as follows:
You should be able to see version information, which ensures that the installation was successful.
After installing Node, you will have babel-plugin-syntax-object-rest-spread
and babel-plugin-transform-object-rest-spread
.
There is a basic difference between these two: spread
will only allow you to read the syntax but transform
will allow you to transform your syntax back to ES5.
After getting this done, you will have to store plugins into the .babelrc
file, as follows:
{ "plugins": ["syntax-object-rest-spread", "transform-object-rest-spread"] }
First we need to create a
package.json
file for our project, which includes the project information and dependencies. Now, open the command prompt/console and navigate to the directory you have created. Run the following command:
Npm init
This command will initialize our app and ask several questions before creating a JSON file named package.json
. The utility will ask questions about the project name, description, entry point, version, author name, dependencies, license information, and so on. Once the command is executed, it will generate a package.json
file in the root directory of your project.
I have created my package.json
file with my requirements, which are shown in the following code:
{ "name": "facebook-api-integration-with-react", "version": "1.2.0", "description": "Web Application to check Like, Comments and Post of your Facebook Friends,
In the preceding code, you can see the name
of the application, the version
of your application, and the description
of your application. Observe the following code snippet:
"scripts": { "lint": "eslint src/ server.js config/ webpack/", "start": "npm run dev", "build": "webpack -p --config webpack/webpack.config.babel.js --progress --colors --define process.env.NODE_ENV='"production"'", "clean": "rimraf dist/", "deploy": "npm run clean && npm run build", "dev": "./node_modules/.bin/babel-node server.js" },
From the preceding code, you can set up your scripts
, to detail such things as how to start
your server, what to build
, what is clean
, and deploy
and dev
. Please make sure whatever path you have defined in the respective variable is correct, otherwise your application won't work as expected. Observe the following code snippet:
"author": "Mehul Bhatt <[email protected]>", "license": "MIT", "keywords": [ "react", "babel", "ES6", "ES7", "async", "await", "webpack", "purecss", "Facebook API" ],
The preceding code shows the author
name, license
(if applicable), and keywords
for your application. Observe the following code snippet:
"devDependencies": { "babel-cli": "^6.3.17", "babel-core": "^6.3.26", "babel-eslint": "^6.0.0", "babel-loader": "^6.2.0", "babel-plugin-react-transform": "^2.0.0-beta1", "babel-plugin-transform-regenerator": "^6.5.2", "babel-polyfill": "^6.5.0", "babel-preset-es2015": "^6.3.13", "babel-preset-react": "^6.3.13", "babel-preset-stage-0": "^6.5.0", "css-loader": "^0.23.0", "enzyme": "^2.4.1", "eslint": "^2.12.0", "eslint-config-airbnb": "^9.0.1", "eslint-plugin-import": "^1.8.1", "eslint-plugin-jsx-a11y": "^1.5.3", "eslint-plugin-react": "^5.2.0", "express": "^4.13.3", "file-loader": "^0.9.0", "imports-loader": "^0.6.5", "json-loader": "^0.5.4", "lolex": "^1.4.0", "react-transform-catch-errors": "^1.0.1", "react-transform-hmr": "^1.0.1", "redbox-react": "^1.2.0", "rimraf": "^2.5.0", "sinon": "^1.17.4", "style-loader": "^0.13.0", "url-loader": "^0.5.7", "webpack": "^1.12.9", "webpack-dev-middleware": "^1.4.0", "webpack-hot-middleware": "^2.6.0", "yargs": "^4.1.0" }, "dependencies": { "classnames": "^2.2.5", "jss": "^5.2.0", "jss-camel-case": "^2.0.0", "lodash.isequal": "^4.0.0", "react": "^15.0.2", "react-addons-shallow-compare": "^15.0.2", "react-dom": "^15.0.2", "reqwest": "^2.0.5", "spin.js": "^2.3.2" } }
Finally, you can see, in the preceding code, the dependencies
of your application which will help you set the required components and fetch data, as well as the frontend stuff. You can also see defined devDependencies
and their versions, which are linked to your application.
After setting up the package.json
file, we have our HTML markup as shown in the following code, named index.html
:
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>React Integration with Facebook API</title> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <div id=" Api-root"></div> <script src="dist/bundle.js"></script> </body> </html>
Configure your application with a unique ID in config.js
:
export default { appId: '1362753213759665', cookie: true, xfbml: false, version: 'v2.5' };
As shown in the preceding code, you can have your configuration in one file. You can name it index.js
. This file includes your appId
, which is very important when it comes to to running your app in your local directory.
To have your ID, you have to register your app in Facebook at https://developers.facebook.com and there you will have to follow these steps:
Enter the required details and click on the Create App ID button.
localhost
as the domain straightaway, it will not be accepted and your application will have errors.To make your localhost accessible, we have to define its platform. Now, please scroll down a bit to access + Add platform:
http://localhost:3000/
and then, in a similar way, you will have to define the same domain in the App Domains field, as shown in the following screenshot:
Now your ID is created, which you can use in your config.js
file to link your app to run in the local server.
After setting up the config.js
file, the next step is to set your required files in that app and inject your dynamic stuff into the HTML ID.
You can import required components, utils, and CSS in the index.js
file and put it in a different folder so that it will not conflict with your configuration
index.js
file:
import React from 'react'; import { render } from 'react-dom'; import App from './components/App'; import 'babel-polyfill'; // import CSS import '../vendor/css/base.css'; import '../vendor/css/bootstrap.min.css'; render( <App />, document.querySelector('#Api-root') );
In the preceding code, you can see that I have imported React
for React-supported files and imported the required CSS files. As a final step, the render
method will do the trick for you after defining your HTML ID into the selector. Make sure
document.querySelector
has the correct selector, otherwise your application will not render with the correct structure.
You can see in the preceding code that I have created one component called App
and imported it.
In the App.js
file, I have imported several components, which helped me to fetch data from my Facebook account with the help of the Facebook API integration.
Observe the following code structure of the App.js
file:
/* global Facebook */ import React, { Component } from 'react'; import Profile from './Profile'; import FriendList from './FriendList'; import ErrMsg from './ErrMsg'; import config from '../../config'; import Spinner from './Spinner'; import Login from './Login'; import emitter from '../utils/emitter'; import { getData } from '../utils/util'; import jss from 'jss';
The preceding imported JavaScript files have been set up to fetch data, building the structure about how it will be executed in your application.
const { classes } = jss.createStyleSheet({ wrapper: { display: 'flex' }, '@media (max-width: 1050px)': { wrapper: { 'flex-wrap': 'wrap' } } }).attach();
The preceding code defines constants to create styles for the wrapper, which will be applied while your page renders in the browser.
class App extends Component { state = { status: 'loading' }; componentWillMount = () => { document.body.style.backgroundColor = '#ffffff'; }; componentWillUnmount = () => { emitter.removeListener('search'); }; componentDidMount = () => { emitter.on('search', query => this.setState({ query })); window.fbAsyncInit = () => { FB.init(config); // show login FB.getLoginStatus( response => response.status !== 'connected' && this.setState({ status: response.status }) ); FB.Event.subscribe('auth.authResponseChange', (response) => { // start spinner this.setState({ status: 'loading' }); (async () => { try { const { profile, myFriends } = await getData(); this.setState({ status: response.status, profile, myFriends }); } catch (e) { this.setState({ status: 'err' }); } })(); }); };
The preceding code extends components, with details of mount/unmount, which we have already covered in previous chapters. If you are still unsure about this area, then please revisit it.
window.fbAsyncInit
will sync the Facebook API with the login setup and it will also validate the status of the login.
It will also async Facebook data such as your profile and friends list, which has separate JavaScript and will be covered later in this chapter.
// Load the SDK asynchronously (function (d, s, id) { const fjs = d.getElementsByTagName(s)[0]; if (d.getElementById(id)) { return; } const js = d.createElement(s); js.id = id; js.src = '//connect.facebook.net/en_US/sdk.js'; fjs.parentNode.insertBefore(js, fjs); }(document, 'script', 'facebook-jssdk')); }; _click = () => { FB.login(() => {}, { scope: ['user_posts', 'user_friends'] }); };
Defining a scope array means we are accessing the user's Facebook friends and posts.
Observe the following screenshot:
In the preceding screenshot, you can see default login permission access in the App Review tab while creating the Facebook login app. We can submit the approval to access any other user information:
mainRender = () => { const { profile, myFriends, status, query } = this.state; if (status === 'err') { return (<ErrMsg />); } else if (status === 'unknown' || status === 'not_authorized') { return <Login fBLogin={this._click} />; } else if (status === 'connected') { return ( <div className={classes.wrapper}> <Profile {...profile} /> <FriendList myFriends={myFriends} query={query} /> </div> ); } return (<Spinner />); }; render() { return ( <div> {this.mainRender()} </div> ); } } export default App;
In the preceding code, the
mainRender
method will render the Profile
,
myFriends
(friend list), and status
and it will return the value in the render return
. You can see, in the render
method, one
<div>
tag; have called it
{this.mainRender()}
to inject the data inside it.
As you know, here we are dealing with third-party API integration. We are not sure about how long we will be connected to that API and how long it will take to load the content. It's better to have a content loader (spinner), which indicates that the user should wait for a while, so we have used the following spinner to show the progress in loading the content on the page. The code for the spinner is also included in the App.js
file. Here's a look at the spinner:
You can also choose your own custom spinner.
Once your application page is ready, your final output should look like the following screenshot, where you will see the basic look and feel, along with the required elements:
Once you hit your local server, the preceding screen will ask your permission to proceed with the login process.
Once you press the Agree button, it will redirect you to the Facebook login page. This can be achieved through the following code (Login.js
):
import React, { PropTypes } from 'react'; import jss from 'jss'; import camelCase from 'jss-camel-case'; jss.use(camelCase());
After importing the React PropTypes
, in the following code you will see that I have defined a constant to create styles for the login page. You can also define styles here and you can put them into one CSS file and have an external file call.
const { classes } = jss.createStyleSheet({ title: { textAlign: 'center', color: '#008000' }, main: { textAlign: 'center', backgroundColor: 'white', padding: '15px 5px', borderRadius: '3px' }, wrapper: { display: 'flex', minHeight: '60vh', alignItems: 'center', justifyContent: 'center' }, '@media (max-width: 600px)': { title: { fontSize: '1em' }, main: { fontSize: '0.9em' } } }).attach();
The following code shows the HTML structure of the login page and it also has the Login.propTypes
defined for the login button:
const Login = ({ fBLogin }) => ( <div className={classes.wrapper}> <div> <h2 className={classes.title}>Please check your friend list on Facebook</h2> <div className={classes.main}> <h4>Please grant Facebook to access your friend list</h4> <button className="btn btn-primary" onClick={fBLogin}>Agree</button> </div> </div> </div> ); Login.propTypes = { fBLogin: PropTypes.func.isRequired }; export default Login;
When you click on the Agree button, your application will be redirected to the Facebook login page. Please refer to the following screenshot:
Once you login with your credentials, it will ask you for permission to access your data as shown in the following screenshot:
Once you have provided the required details and pressed the Continue as button, it will give you the final screen with the final output.
For security reasons, I have blurred my friends' profile pictures and their names, but you will get the same layout in your Facebook account. Now you're thinking about fetching a friends list in your application, right? So, with help of the following code, I have fetched a list in my custom app.
FriendList.js
is imported in the App.js
file:
import React, { PropTypes } from 'react'; import FriendItem from './FriendItem'; import { MAX_OUTPUT } from '../utils/constants'; import jss from 'jss'; import camelCase from 'jss-camel-case'; jss.use(camelCase());
As we can see in the preceding code snippets, we are also importing React
, constants
, and FriendItem
to get the data. Here we are just importing FriendItem
but it will have a separate file to deal with this:
const { classes } = jss.createStyleSheet({ nodata: { fontSize: '1.5em', display: 'flex', justifyContent: 'center', alignItems: 'center', textAlign: 'center', color: 'white', minHeight: '100vh', }, wrapper: { flex: '3' }, '@media (max-width: 1050px)': { wrapper: { flex: '1 1 100%' }, nodata: { minHeight: 'auto' } } }).attach();
The preceding code defines the wrapper styles for the friends list content. As I said earlier, you can also have those in a separate CSS file and have an external call, whichever is convenient for you.
const emptyResult = (hasFriends, query) => { return ( <div className={classes.nodata}> {hasFriends ? `No results for: "${query}"` : 'No friends to show'} </div> ); };
In the preceding code, you can see a condition to validate whether someone has friends or no friends. If someone does not have a friends list in their Facebook account, it will show the aforementioned message.
const renderFriends = ({ myFriends, query }) => { const result = myFriends.reduce((prev, curr, i) => { if (curr.name.match(new RegExp(query, 'i'))) { prev.push(<FriendItem key={i} rank={i + 1} {...curr} />); } return prev; }, []); return result.length > 0 ? result : emptyResult (!!myFriends.length, query); }; const FriendList = (props) => ( <div className={classes.wrapper}> {renderFriends(props)} </div> ); FriendList.propTypes = { myFriends: PropTypes.array.isRequired, query: PropTypes.string }; export default FriendList;
If your account has friends, then you will get a full list of friends including their profile pictures, likes, comments, and the number of posts, so in this way you can also have Facebook API integration with React.