Pagination for Custom Post types

Prev and Next button

$our_current_page = get_query_var( 'paged' );

$query = new \WP_Query(
   [
      'post_type'              => 'post-type-name',
      'post_status'            => 'publish',
      'posts_per_page'         => 3,
      'paged'                  => $our_current_page,
      'update_post_meta_cache' => false,
      'update_post_term_cache' => false,
   ]
);

    if ( $query->have_posts() ) {

      while ( $query->have_posts() ) {
         $query->the_post();
         the_title();
      } // end while

      previous_posts_link();
      next_posts_link( 'Next page', $query->max_num_pages );

   } // end if

Numbered Pagination

Create a Custom pagination function

/**
 * Custom pagination
 */
function custom_pagination( $query ) {

   $allowed_tags = [
      'span' => [
         'class' => [],
      ],
      'i'    => [
         'class' => [],
      ],
      'a'    => [
         'class' => [],
         'href'  => [],
      ],
   ];

   printf(
      '<nav class="ninetrade-pagination clearfix">%s</nav>',
      wp_kses(
         paginate_links(
            [
               'prev_text' => '<i class="fa fa-angle-left" aria-hidden="true"></i> ' . __( 'Previous', 'ninetrade' ),
               'next_text' => __( 'Next', 'ninetrade' ) . ' <i class="fa fa-angle-right" aria-hidden="true"></i>',
               'total'     => $query->max_num_pages
            ]
         ),
         $allowed_tags
      )
   );
}

Now use this custom function with the query

$our_current_page = get_query_var( 'paged' );

$query = new \WP_Query(
   [
      'post_type'              => 'post-type-name',
      'post_status'            => 'publish',
      'posts_per_page'         => 3,
      'paged'                  => $our_current_page,
      'update_post_meta_cache' => false,
      'update_post_term_cache' => false,
   ]
);

if ( $query->have_posts() ) {

   while ( $query->have_posts() ) {
      $query->the_post();
      //
      // Post Content here

      the_title();
      //
   } // end while

   wp_reset_postdata();

   custom_pagination( $query );

}

Date Functions and Formats

Date in PHP

<time data-publish-date="<?php echo esc_attr( sprintf( '%s 00:01', current_time( 'Y-m-d', false ) ) ); ?>" data-relative-time-timezone="<?php echo esc_attr( get_option( 'timezone_string' ) ); ?>">
	<span class="day">
		<?php echo esc_html( sprintf( '%s, ', current_time( 'l', false ) ) ); ?>
	</span>
	<?php echo esc_html( current_time( 'F d, Y', false ) ); ?>
</time>

Date in WordPress

echo get_the_date( 'F d, Y', $post_id );

Using Templates in WordPress

In themes:

get_template_part( 'slug-name', 'name' );
We should keep our templates inside template-parts directory.
So lets say our template file is in:
themes/theme-name/template-parts/home/home-my-template.php
To include this template you will write ( for e.g. inside front-page.php )

get_template_part( 'template-parts/home/home', 'my-template' );

For e.g. our template file is in:
themes/theme-name/template-parts/home/my-template.php

get_template_part( 'template-parts/home', 'my-template' );

In Plugin,

For e.g. our template file is in:
plugins/plugin-name/templates/my-template.php

load_template( PLUGIN_DIR_PATH . '/templates/my-template.php' );

If we want to pass data to the template, we do it like so :

set_query_var( 'name', 'Imran' );
load_template( PLUGIN_DIR_PATH . '/templates/my-template.php' );

Now we can access this variable in template file as $name.

Using Underscore JS _.template() in WordPress

Many times we come across a situation in JavaScript where we have to generate dynamic html

let content = '<li class="list-item">' +
	'<div class="details">' +
			'<h3>{ title }</h3>' +
			'<p>{ description }</p>' ++
	'</div>' +
'</li>';

You can see the code above looks messy and difficult to read. 
WordPress recommends to use underscore templates.
WordPress already has support for underscore.js library. All you have you to do is enqueue it like so :

wp_register_script( 'my-script', 'path/to/your/main.js', [ 'jquery', 'underscore' ], false, true );

Then you can create a template in a php file e.g. my-template.php and hook it to the wp_footer hook using add_action . This will add your script at the bottom of your page . The variables that you pass will be available in propertyName

<%= … %> is used to pass variables.
<% … %> is used to insert JS code.
<%- … %> is used for HTML escaped value

<?php
add_action( 'wp_footer', 'my_data_template' );

function my_data_template() { ?>

	<script type="text/html" id="my-template">
		<li class="list-item <%= className %>">
			<div class="details">
				<h3><%= title %></h3>
				<p><%= description %></p>
			</div>
		</li>
	</script>
<?php }

Make sure you include this file ( e.g. in functions.php )

Now all you have to do is get the html content of the above script. Call the _.template() by passing this template inside of it. _.template() will return a function which you can then use to pass the data inside of it and append it where you want like so :

	var template = jQuery("#my-template").html();
	var templateFunc = _.template( template );


	jQuery("body").html( templateFunc( {title: 'Imran', description: 'my desc', className: 'some-class' } ));

Using underscore template in WordPress

Many times we come across a situation in JavaScript where we have to generate dynamic html

let content = '<li class="list-item">' +
	'<div class="details">' +
			'<h3>{ title }</h3>' +
			'<p>{ description }</p>' ++
	'</div>' +
'</li>';

You can see the code above looks messy and difficult to read.
WordPress recommends to use underscore templates.
WordPress already has support for underscore.js library. All you have you to do is enqueue it like so :

wp_register_script( 'my-script', 'path/to/your/main.js', [ 'jquery', 'wp-util' ], false, true );

Then you can create a template in a php file e.g. my-template.php and hook it to the wp_footer hook using add_action . This will add your script at the bottom of your page. The script’s type is text/html and it has an id that must start with tmpl- . The variables that you pass will be available data.propertyName

<?php
add_action( 'wp_footer', 'my_data_template' );

function my_data_template() { ?>

	<script type="text/html" id="tmpl-my-template">
		<li class="list-item">
			<div class="details">
				<h3>{{{data.title}}}</h3>
				<p>{{{data.description}}}</p>
			</div>
		</li>
	</script>
<?php }

There are three tags you’ll want to know:

  • {{ var }} is used for HTML-escaped data.
  • {{{ var }}} is used for raw data (not escaped).
  • <# some_code() #> allows you to evaluate any JavaScript code.

Now all you have to do is use this in your main.js file like so :

// wp.template returns function which we can hold in postTemplate
const postTemplate = wp.template( 'my-template' );

const myData = {
   title   : 'This is awesome!',
   description  : 'This is description',
}

// We can pass the data inside postTemplate()
$( '.your-selector' ).html( postTemplate( myData ) );

This will insert your template with id tmpl-my-template inside the element with classname your-selector. Notice that when passing the id in wp.template(), we do not pass the prefix. So instead of tmpl-my-template we put my-template

Fix PHPCS errors in WordPress

Visibility must be declared on method “__construct”

Add public before the class method

Detected usage of a non-sanitized input variable: $_POST[‘xyz’]

You need to sanitize it. E.g. esc_html( $_POST['xyz'] ) or sanitize_text_field( $_POST['xyz'] )

 Detected usage of a possibly undefined superglobal array index: $_POST[‘query’]. Use isset() or empty() to check

Wrap it inside empty() e.g. empty( $_POST['query'] )

Object property “$errorCode” is not in valid snake_case format, try “$error_code”

You need to write your variable in snake case e.g. $var_name instead of $varName

Object Caching In WordPress

As a CMS, WordPress is heavily dependent on its database, and database efficiency is crucial to scaling( capability to handle increased/growing workload ) WordPress. If requests to your website generates a large number of database queries, your database servers resource can become overwhelmed. This will reduce your site’s performance and uptime.

To avoid multiple database queries , WordPress stores its data in object cache as a key-value pairs in $wp_object_cache variable, in cache.php.

The cache.php file has WP_Object_Cache class, which is used for caching data. We should not use the class directly but should rather use a set of wp_cache functions which allow you to store key-value pairs in memory  and you can also set an expiration time for keys.

wp_cache_get() gets value the cached object, wp_cache_delete deletes the data for the cache for given key wp_cache_flush() clears all cached data.

In WordPress, the object cache functionality provided by WP_Object_Cache, and the Transient API are great solutions for improving performance on long-running queries, complex functions, or similar.

On a regular WordPress install, the difference between transients and the object cache is that transients are persistent and would write to the options table, while the object cache only persists for the particular page load.

By default, the data stored in Object Cache stays in the memory only for a duration of an HTTP request( single page load ) . Once the request is served the data is no longer available. So WordPress Object cache is non-persistent by default.

To make the object cache persistent across all HTTP requests or to override wordpress default caching, you need to create a file called object-cache.php in wp-content which needs to override all the functions of WordPress Object Cache.This overwritten functions can store the key-value pairs in any persistent caching storage system such as Redis, Memcached etc( which are open source memory caching tools )

There are lots of popular plugins like WP Redis and Memcached Object Cache which make the object cache persistent. They store key-value pairs in Redis and Memchached respectively.

On environments with a persistent caching mechanism (i.e. Memcache, Redis, or similar) enabled, the transient functions become wrappers for the normal WP_Object_Cache functions. The objects are identically stored in the object cache and will be available across page loads.

Every WordPress API makes a copy of the data in cache, during its CRUD process.

Example :

get_option call is made

  1. WordPress runs wp_load_alloptions()
  2. If your option is autoloaded, wp_load_alloptions() returns an array of autoloaded options
  3. If your option is not autoloaded, WordPress returns the value of that option from the cache, if cache is not present then it returns it from the database and set a cache value for it.
  4. If the option name was invalid, WordPress stores that option name in ‘notoptions’ cached array, and will check the ‘notoptions’ array first if subsequent calls are made to the same non existing option name.

So options are loaded into the object cache so when you request an option there’s a 99% chance that request will never hit the database.


Storybook for React

In this blog, we will talk about what is storybook, why should we use it and how to set up storybook for your React project using storybook and create-react-app.

Image result for storybook react

So what is storybook? Storybook is an open source tool that is used for developing UI components in isolation for React, Vue, and Angular.

Why should we use Storybook?

Building User Interfaces is more difficult these days. You are responsible for the layout, logic, personalization, performance, internationalization, accessibility, mobile, browser. And all of that has to work together seamlessly.

Components solve some of these problems but create some too. They are dependent on each other. Changes to one can end up breaking all. And keeping track of large no. of components is difficult. And you end up reinventing the same thing over and over again.

Storybook solves this problem because you can build UI components in isolation. Developers don’t get distracted by flaky data, business login or unfinished API. Developers can focus on hard to reach use cases. It provides reusability. It helps you collaborate with designers, project managers, and other developers.
You can browse components and their use cases in one place. And it’s easy to drop components right into your app.

"Abstraction, Isolation, Autonomy" - Norbert de Langen

A good abstraction is a key to good software. If you create abstractions where you shouldn’t, you create complexity. If you don’t create abstractions where you should, you create complexity.

Complexity is like a dragon, that if you don’t combat effectively, you are feeding it and making the problem worse. Isolation is a possible result of good abstraction. React components abstract a section of UI

Features of Storybook

  • UI development environment for UI components
  • You can visualize different states of your UI components.
  • You can develop them interactively
  • It runs outside of your app.
  • You can develop without app specific dependencies and requirements.

Installation and set up

Let’s install storybook globally first.

npm i -g @storybook/cli

Now let’s create a react application using create-react-app

cd ~
create-react-app my-storybook
cd my-storybook

Install storybook in your react application. getstorybook command adds storybook support to your “Create React App” based project.

cd my-storybook
getstorybook

Start the storybook server

cd my-storybook
yarn run storybook

Then you can create a directory called components inside src directory and add your components in the stories /index.js like so:

storiesOf('Header', module)
.add('header', () => <Header/>);
.add('footer', () => <Header/>);

So technically, a story is a function that returns something that can be rendered to screen. A Storybook can be comprised of many stories for many components.

Actions

The events can be seen in action

Directory Structure

Add Ons:

Storybook comes with a way to list stories and visualize them. Add-ons implement extra features for Storybooks to make them more useful. Storybook comes with Knobs, Actions, Source, Docs, Accessibility etc.
You can also add your own custom addons as well.

We will learn more about add ons in the upcoming blogs.

Google Maps in React: Autocomplete Location Search | Draggable Marker | Marker Infobox

I will teach you how to integrate Google Maps in your React Project.
You will also learn how to create an autocomplete location search and draggable marker. When you search the location and select one the marker will automatically move to that location and display the address in the infobox.
We will use the following npm modules to achieve this:
1-react
2-react-google-maps 
3-react-google-autocomplete
4-react-geocode

YouTube Tutorial:

Completed Code: https://github.com/imranhsayed/google-maps-in-react

Step 1Install Boilerplate: You can either use your own project or You can clone the boilerplate from below link for testing.

git clone https://github.com/imranhsayed/react-node-boilerplate
cd react-node-boilerplate
npm cache clean --force // in root dir
npm install
cd client // in client dir
npm cache clean --force
npm install

Step 2: Install react-google-maps, react-google-autocomplete and react-geocode npm modules.

cd client
npm i react-google-maps react-google-autocomplete react-geocode

Step 3: Create Map.js Component

import React from 'react'
import { withGoogleMap, GoogleMap, withScriptjs, InfoWindow, Marker } from "react-google-maps";
import Geocode from "react-geocode";
Geocode.setApiKey("AIzaSyDGe5vjL8wBmilLzoJ0jNIwe9SAuH2xS_0");
Geocode.enableDebug();
class Map extends React.Component{
constructor( props ){
super( props );
this.state = {
address: '',
city: '',
area: '',
state: '',
mapPosition: {
lat: this.props.center.lat,
lng: this.props.center.lng
},
markerPosition: {
lat: this.props.center.lat,
lng: this.props.center.lng
}
}
}
/**
* Get the current address from the default map position and set those values in the state
*/
componentDidMount() {
Geocode.fromLatLng( this.state.mapPosition.lat , this.state.mapPosition.lng ).then(
response => {
const address = response.results[0].formatted_address,
addressArray = response.results[0].address_components,
city = this.getCity( addressArray ),
area = this.getArea( addressArray ),
state = this.getState( addressArray );

console.log( 'city', city, area, state );

this.setState( {
address: ( address ) ? address : '',
area: ( area ) ? area : '',
city: ( city ) ? city : '',
state: ( state ) ? state : '',
} )
},
error => {
console.error(error);
}
);
};
/**
* Component should only update ( meaning re-render ), when the user selects the address, or drags the pin
*
* @param nextProps
* @param nextState
* @return {boolean}
*/
shouldComponentUpdate( nextProps, nextState ){
if (
this.state.markerPosition.lat !== this.props.center.lat ||
this.state.address !== nextState.address ||
this.state.city !== nextState.city ||
this.state.area !== nextState.area ||
this.state.state !== nextState.state
) {
return true
} else if ( this.props.center.lat === nextProps.center.lat ){
return false
}
}
/**
* Get the city and set the city input value to the one selected
*
* @param addressArray
* @return {string}
*/
getCity = ( addressArray ) => {
let city = '';
for( let i = 0; i < addressArray.length; i++ ) {
if ( addressArray[ i ].types[0] && 'administrative_area_level_2' === addressArray[ i ].types[0] ) {
city = addressArray[ i ].long_name;
return city;
}
}
};
/**
* Get the area and set the area input value to the one selected
*
* @param addressArray
* @return {string}
*/
getArea = ( addressArray ) => {
let area = '';
for( let i = 0; i < addressArray.length; i++ ) {
if ( addressArray[ i ].types[0] ) {
for ( let j = 0; j < addressArray[ i ].types.length; j++ ) {
if ( 'sublocality_level_1' === addressArray[ i ].types[j] || 'locality' === addressArray[ i ].types[j] ) {
area = addressArray[ i ].long_name;
return area;
}
}
}
}
};
/**
* Get the address and set the address input value to the one selected
*
* @param addressArray
* @return {string}
*/
getState = ( addressArray ) => {
let state = '';
for( let i = 0; i < addressArray.length; i++ ) {
for( let i = 0; i < addressArray.length; i++ ) {
if ( addressArray[ i ].types[0] && 'administrative_area_level_1' === addressArray[ i ].types[0] ) {
state = addressArray[ i ].long_name;
return state;
}
}
}
};
/**
* And function for city,state and address input
* @param event
*/
onChange = ( event ) => {
this.setState({ [event.target.name]: event.target.value });
};
/**
* This Event triggers when the marker window is closed
*
* @param event
*/
onInfoWindowClose = ( event ) => {
};
render(){
const AsyncMap = withScriptjs(
withGoogleMap(
props => (
<GoogleMap google={this.props.google}
defaultZoom={this.props.zoom}
defaultCenter={{ lat: this.state.mapPosition.lat, lng: this.state.mapPosition.lng }}
>
</GoogleMap>
)
)
);
let map;
if( this.props.center.lat !== undefined ) {
map = <div>
<div>
<div className="form-group">
<label htmlFor="">City</label>
<input type="text" name="city" className="form-control" onChange={ this.onChange } readOnly="readOnly" value={ this.state.city }/>
</div>
<div className="form-group">
<label htmlFor="">Area</label>
<input type="text" name="area" className="form-control" onChange={ this.onChange } readOnly="readOnly" value={ this.state.area }/>
</div>
<div className="form-group">
<label htmlFor="">State</label>
<input type="text" name="state" className="form-control" onChange={ this.onChange } readOnly="readOnly" value={ this.state.state }/>
</div>
<div className="form-group">
<label htmlFor="">Address</label>
<input type="text" name="address" className="form-control" onChange={ this.onChange } readOnly="readOnly" value={ this.state.address }/>
</div>
</div>
<AsyncMap
googleMapURL="https://maps.googleapis.com/maps/api/js?key=AIzaSyDGe5vjL8wBmilLzoJ0jNIwe9SAuH2xS_0&libraries=places"
loadingElement={
<div style={{ height: `100%` }} />
}
containerElement={
<div style={{ height: this.props.height }} />
}
mapElement={
<div style={{ height: `100%` }} />
}
/>
</div>
} else {
map = <div style={{height: this.props.height}} />
}
return( map )
}
}
export default Map

Marker Component

import { Marker } from "react-google-maps";
{/*Marker*/}
<Marker google={this.props.google}
name={'Dolores park'}
draggable={true}
onDragEnd={ this.onMarkerDragEnd }
position={{ lat: this.state.markerPosition.lat, lng: this.state.markerPosition.lng }}
/>
<Marker />

InfoWindow Component

import { InfoWindow } from "react-google-maps";
component Map extends Component {
/**
* This Event triggers when the marker window is closed
*
* @param event
*/
onInfoWindowClose = ( event ) => {
};
render(){
return(
{/* InfoWindow on top of marker */}
<InfoWindow
onClose={this.onInfoWindowClose}
position={{ lat: ( this.state.markerPosition.lat + 0.0018 ), lng: this.state.markerPosition.lng }}
>
<div>
<span style={{ padding: 0, margin: 0 }}>{ this.state.address }</span>
</div>
</InfoWindow>
)
}

Autocomplete or Search location

import Autocomplete from 'react-google-autocomplete';
component Map extends Component {
/**
* When the user types an address in the search box
* @param place
*/
onPlaceSelected = ( place ) => {
const address = place.formatted_address,
addressArray = place.address_components,
city = this.getCity( addressArray ),
area = this.getArea( addressArray ),
state = this.getState( addressArray ),
latValue = place.geometry.location.lat(),
lngValue = place.geometry.location.lng();
// Set these values in the state.
this.setState({
address: ( address ) ? address : '',
area: ( area ) ? area : '',
city: ( city ) ? city : '',
state: ( state ) ? state : '',
markerPosition: {
lat: latValue,
lng: lngValue
},
mapPosition: {
lat: latValue,
lng: lngValue
},
})
};
render(){
return(
{/* For Auto complete Search Box */}
<Autocomplete
style={{
width: '100%',
height: '40px',
paddingLeft: '16px',
marginTop: '2px',
marginBottom: '100px'
}}
onPlaceSelected={ this.onPlaceSelected }
types={['(regions)']}
/>
)
}

Putting Everything together

import React from 'react'
import { withGoogleMap, GoogleMap, withScriptjs, InfoWindow, Marker } from "react-google-maps";
import Autocomplete from 'react-google-autocomplete';
import Geocode from "react-geocode";
Geocode.setApiKey("AIzaSyDGe5vjL8wBmilLzoJ0jNIwe9SAuH2xS_0");
Geocode.enableDebug();
class Map extends React.Component{
constructor( props ){
super( props );
this.state = {
address: '',
city: '',
area: '',
state: '',
mapPosition: {
lat: this.props.center.lat,
lng: this.props.center.lng
},
markerPosition: {
lat: this.props.center.lat,
lng: this.props.center.lng
}
}
}
/**
* Get the current address from the default map position and set those values in the state
*/
componentDidMount() {
Geocode.fromLatLng( this.state.mapPosition.lat , this.state.mapPosition.lng ).then(
response => {
const address = response.results[0].formatted_address,
addressArray = response.results[0].address_components,
city = this.getCity( addressArray ),
area = this.getArea( addressArray ),
state = this.getState( addressArray );

console.log( 'city', city, area, state );

this.setState( {
address: ( address ) ? address : '',
area: ( area ) ? area : '',
city: ( city ) ? city : '',
state: ( state ) ? state : '',
} )
},
error => {
console.error(error);
}
);
};
/**
* Component should only update ( meaning re-render ), when the user selects the address, or drags the pin
*
* @param nextProps
* @param nextState
* @return {boolean}
*/
shouldComponentUpdate( nextProps, nextState ){
if (
this.state.markerPosition.lat !== this.props.center.lat ||
this.state.address !== nextState.address ||
this.state.city !== nextState.city ||
this.state.area !== nextState.area ||
this.state.state !== nextState.state
) {
return true
} else if ( this.props.center.lat === nextProps.center.lat ){
return false
}
}
/**
* Get the city and set the city input value to the one selected
*
* @param addressArray
* @return {string}
*/
getCity = ( addressArray ) => {
let city = '';
for( let i = 0; i < addressArray.length; i++ ) {
if ( addressArray[ i ].types[0] && 'administrative_area_level_2' === addressArray[ i ].types[0] ) {
city = addressArray[ i ].long_name;
return city;
}
}
};
/**
* Get the area and set the area input value to the one selected
*
* @param addressArray
* @return {string}
*/
getArea = ( addressArray ) => {
let area = '';
for( let i = 0; i < addressArray.length; i++ ) {
if ( addressArray[ i ].types[0] ) {
for ( let j = 0; j < addressArray[ i ].types.length; j++ ) {
if ( 'sublocality_level_1' === addressArray[ i ].types[j] || 'locality' === addressArray[ i ].types[j] ) {
area = addressArray[ i ].long_name;
return area;
}
}
}
}
};
/**
* Get the address and set the address input value to the one selected
*
* @param addressArray
* @return {string}
*/
getState = ( addressArray ) => {
let state = '';
for( let i = 0; i < addressArray.length; i++ ) {
for( let i = 0; i < addressArray.length; i++ ) {
if ( addressArray[ i ].types[0] && 'administrative_area_level_1' === addressArray[ i ].types[0] ) {
state = addressArray[ i ].long_name;
return state;
}
}
}
};
/**
* And function for city,state and address input
* @param event
*/
onChange = ( event ) => {
this.setState({ [event.target.name]: event.target.value });
};
/**
* This Event triggers when the marker window is closed
*
* @param event
*/
onInfoWindowClose = ( event ) => {
};
/**
* When the user types an address in the search box
* @param place
*/
onPlaceSelected = ( place ) => {
const address = place.formatted_address,
addressArray = place.address_components,
city = this.getCity( addressArray ),
area = this.getArea( addressArray ),
state = this.getState( addressArray ),
latValue = place.geometry.location.lat(),
lngValue = place.geometry.location.lng();
// Set these values in the state.
this.setState({
address: ( address ) ? address : '',
area: ( area ) ? area : '',
city: ( city ) ? city : '',
state: ( state ) ? state : '',
markerPosition: {
lat: latValue,
lng: lngValue
},
mapPosition: {
lat: latValue,
lng: lngValue
},
})
};
/**
* When the marker is dragged you get the lat and long using the functions available from event object.
* Use geocode to get the address, city, area and state from the lat and lng positions.
* And then set those values in the state.
*
* @param event
*/
onMarkerDragEnd = ( event ) => {
console.log( 'event', event );
let newLat = event.latLng.lat(),
newLng = event.latLng.lng(),
addressArray = [];
Geocode.fromLatLng( newLat , newLng ).then(
response => {
const address = response.results[0].formatted_address,
addressArray = response.results[0].address_components,
city = this.getCity( addressArray ),
area = this.getArea( addressArray ),
state = this.getState( addressArray );
this.setState( {
address: ( address ) ? address : '',
area: ( area ) ? area : '',
city: ( city ) ? city : '',
state: ( state ) ? state : ''
} )
},
error => {
console.error(error);
}
);
};
render(){
const AsyncMap = withScriptjs(
withGoogleMap(
props => (
<GoogleMap google={this.props.google}
defaultZoom={this.props.zoom}
defaultCenter={{ lat: this.state.mapPosition.lat, lng: this.state.mapPosition.lng }}
>
{/* For Auto complete Search Box */}
<Autocomplete
style={{
width: '100%',
height: '40px',
paddingLeft: '16px',
marginTop: '2px',
marginBottom: '100px'
}}
onPlaceSelected={ this.onPlaceSelected }
types={['(regions)']}
/>
{/*Marker*/}
<Marker google={this.props.google}
name={'Dolores park'}
draggable={true}
onDragEnd={ this.onMarkerDragEnd }
position={{ lat: this.state.markerPosition.lat, lng: this.state.markerPosition.lng }}
/>
<Marker />
{/* InfoWindow on top of marker */}
<InfoWindow
onClose={this.onInfoWindowClose}
position={{ lat: ( this.state.markerPosition.lat + 0.0018 ), lng: this.state.markerPosition.lng }}
>
<div>
<span style={{ padding: 0, margin: 0 }}>{ this.state.address }</span>
</div>
</InfoWindow>
</GoogleMap>
)
)
);
let map;
if( this.props.center.lat !== undefined ) {
map = <div>
<div>
<div className="form-group">
<label htmlFor="">City</label>
<input type="text" name="city" className="form-control" onChange={ this.onChange } readOnly="readOnly" value={ this.state.city }/>
</div>
<div className="form-group">
<label htmlFor="">Area</label>
<input type="text" name="area" className="form-control" onChange={ this.onChange } readOnly="readOnly" value={ this.state.area }/>
</div>
<div className="form-group">
<label htmlFor="">State</label>
<input type="text" name="state" className="form-control" onChange={ this.onChange } readOnly="readOnly" value={ this.state.state }/>
</div>
<div className="form-group">
<label htmlFor="">Address</label>
<input type="text" name="address" className="form-control" onChange={ this.onChange } readOnly="readOnly" value={ this.state.address }/>
</div>
</div>
<AsyncMap
googleMapURL="https://maps.googleapis.com/maps/api/js?key=AIzaSyDGe5vjL8wBmilLzoJ0jNIwe9SAuH2xS_0&libraries=places"
loadingElement={
<div style={{ height: `100%` }} />
}
containerElement={
<div style={{ height: this.props.height }} />
}
mapElement={
<div style={{ height: `100%` }} />
}
/>
</div>
} else {
map = <div style={{height: this.props.height}} />
}
return( map )
}
}
export default Map

Step 4: Import Map into another component

// Now export the above Map component into another component by passing the props values
class NewCompo extends Component {
render() {
return(
<Map
google={this.props.google}
center={{lat: 18.5204, lng: 73.8567}}
height='300px'
zoom={15}
/>
)
}
}