Saturday, February 15, 2020

How to write a simple React plugin, publish it to npm, and deploy it to Github pages

Getting started


Our target is to create and publish a ReactJS plugin so we can access it via NPM directly.

I'm going to creat react plugin using create-react-library which is a CLI for easily creating reusable react libraries. This CLI has a bunch of features and will help us in generating a full featured project as well as plugin.

To use create-react-library, we’ll need to install it globally:

npm install -g create-react-library


The above command will install create-react-library globally and we can generate a new module from any directory.

Now execute following command to create an module which will ask you some basic questions about your plugin and will take few minutes to complete installation of reactjs plugin:

create-react-library



After plugin project created navigate to project directory using

cd react-profile-image-box


Now, you need to run the plugin (for watching any changes that you make to it) and the example. In one tab, you can run:

npm start


And, in another tab, you need to run the example app:

cd ./example && npm start


The last command will run a create-react-app project which imports your plugin. If you make any changes to your plugin, it will get reflected in the example app. You can view the current status of your plugin by visiting http://localhost:3000.

import React, { Component } from 'react'
import PropTypes from 'prop-types'

import styles from './styles.css'

export default class ProfileImageBox extends Component {
  /**
     * src: The src for img tag
     * alt: Alt text for img tag
     * allowUpload: Boolean field to set if image can be changed or not
     * onFileChange: A function that will receive file change event
     */
  static propTypes = {
    src: PropTypes.string,
    alt: PropTypes.string,
    allowUpload: PropTypes.bool,
    onFileChange: PropTypes.func
  }

  static defaultProps = {
    allowUpload: false,
    onFileChange: function(e, additionalParams) {
      alert("You need to implement onFileChange(e) method")
    }
  }

  constructor (props) {
    super(props)
  }

  render() {
    const {
      src, alt, allowUpload, onFileChange
    } = this.props

    return (
      <div className={styles.react_profile_image_box_container}>
        {allowUpload ? (<input 
          className={styles.react_profile_image_box_upload_profile_image_input}
          onChange={(e) => onFileChange(e)} 
          type="file"/>) : ''}
        
        <img 
          className={styles.react_profile_image_box_rounded_circle} 
          alt={alt} 
          src={src} 
          data-holder-rendered="true"/>
      </div>
    )
  }
}

You should use above plugin as below:

import React, { Component } from 'react'

import ProfileImageBox from 'react-profile-image-box'

export default class App extends Component {
  state = {
    src: "http://test.com/avatar_images_by_user/72"
  }

  onFileChange(e, additionalParams) {
    console.log(e.target.files);
    console.log(additionalParams);
    this.setState({src: "http://test.com/avatar_images_by_user/70"});
    // YOU SHOULD UPLOAD YOUR FILE FROM HERE
    // AND SET SCR AGAIN TO SEE LATEST PRICTURE
  }

  render () {
    return (
      <div>
        <ProfileImageBox 
          alt="Alt Text" 
          allowUpload={true} 
          onFileChange={(e) => this.onFileChange(e, {type: 'user-image'})} 
          src={this.state.src}/>
      </div>
    )
  }
}

You can now push your code to git repository

Our main target is to publishing our plugin to npm


create-react-library already has a feature through which we can deploy the example folder to Github pages. You just need to run the following command:

Be sure run npm login to login to npm server and then run npm publish.


Npm package is published now https://www.npmjs.com/package/react-profile-image-box



Saturday, February 1, 2020

ReactJS Create React Modal Open Popup Using reactjs-popup Dependency

In this tutorial, we will use the react-popup package which is a simple and Powerful react component. It's simple just add dependency

import Popup from "reactjs-popup";

which you can add to your project by following command

npm add reactjs-popup --save

Because reactjs-popup provides a child as function pattern, you have full control on Popup state
Full code example given below:
import React, { Component } from "react";
import "./styles.css";
import Popup from "reactjs-popup";

class App extends Component {
  constructor() {
    super();
    this.state = {
      open: false
    };
    this.openModal = this.openModal.bind(this);
    this.closeModal = this.closeModal.bind(this);
    this.popupOnClose = this.popupOnClose.bind(this);
  }

  openModal() {
    this.setState({ open: true });
  }

  closeModal() {
    this.setState({ open: false });
  }

  popupOnClose() {}

  render() {
    return (
      <div>
        <span onClick={this.openModal}>Click here to open Popup</span>
        <Popup
          open={this.state.open}
          className="popup-modal-container-box"
          modal
          onOpen={e => this.popupOnClose(e)}
          onClose={this.popupOnClose}
          lockScroll={true}
          closeOnDocumentClick={false}
        >
          <h1>HELLO POPUP</h1>
          <span onClick={this.closeModal}>CLOSE</span>
        </Popup>
      </div>
    );
  }
}
export default App;
Full example is created on CodeSandbox.IO
https://codesandbox.io/s/reactjs-create-react-modal-open-popup-using-reactjs-popup-dependency-qthyq

Friday, January 31, 2020

ReactJS - You tried to redirect to the same route you're currently on

It's a common problem when you redirect on same route will give a warning like You tried to redirect to the same route you're currently on: /profile/2. It's because of when we define Route we can not define for every parameters like 1, 2, 3 etc. Normally we define our Route like:

<Route path="/profile/:id" component={Profile} />

And this will handle every URL like http://example.com/profile/1, http://example.com/profile/2 etc.
But sometimes when we use Redirect component to redirect to another profile page from current profile page using the below code

return <Redirect to={"/profile/" + this.state.id} push={true} />;

The above warning thrown because our Route is same for all URL like /profile/1 as well as /profile/2.
To avoid this warning we need to define key to our Route like below

<Route path="/profile/:id" render={props => { return <Profile {...props} key={props.match.params.id} />; }} />
Full example is created on CodeSandbox.IO https://codesandbox.io/s/you-tried-to-redirect-to-the-same-route-youre-currently-on-063ot

Thursday, January 2, 2020

Request Mocking In Grails For Back-end/Background Threads | Mock Request With Session

Request Mocking In Grails For Back-end/Background Threads | Mock Request With Session

package com.pkm.util

import grails.gsp.PageRenderer
import grails.util.Holders
import org.codehaus.groovy.grails.web.servlet.mvc.GrailsHttpSession
import org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequest
import org.springframework.web.context.request.RequestContextHolder

import javax.servlet.ServletContext
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpSession
/**
 * Created by pritom on 16/08/2017.
 */
class HibernateRequestUtils {
    static GrailsWebRequest getRequest() {
        return RequestContextHolder.getRequestAttributes()
    }

    static HttpSession getSession() {
        return request?.session
    }

    static void setValueToSession(String key, def value) {
        session.putAt(key, value)
    }

    static def getValueFromSession(String key) {
        return session.getAt(key)
    }

    static boolean isBound() {
        HttpServletRequest.isBound()
    }

    static boolean hasSession() {
        session != null
    }

    static def mock(Closure closure = null) {
        return HttpServletRequest.mock(closure)
    }

    static {
        HttpServletRequest.metaClass.static.with {
            isBound = {
                RequestContextHolder.requestAttributes != null
            }
            mock = { closure = null ->
                HttpServletRequest _request = PageRenderer.PageRenderRequestCreator.createInstance("/page/dummy")
                _request.IS_DUMMY = true
                _request."javax.servlet.include.servlet_path" = "/page/dummy.dispatch"
                GrailsWebRequest webRequest = new GrailsWebRequest(
                        _request,
                        PageRenderer.PageRenderResponseCreator.createInstance(new PrintWriter(new StringWriter())),
                        Holders.servletContext
                ) {
                    private MockedHttpSession _session

                    MockedHttpSession getSession() {
                        if (this._session == null) {
                            this._session = new MockedHttpSession()
                        }
                        return this._session
                    }
                }
                RequestContextHolder.setRequestAttributes(webRequest)
                if (closure) {
                    def returned = closure()
                    RequestContextHolder.resetRequestAttributes()
                    return returned
                }
                return webRequest
            }
        }
    }
}

class MockedHttpSession extends GrailsHttpSession {
    MockedHttpSession() {
        super(null)
    }

    private LinkedHashMap attributes = [:]

    Object getAttribute(String name) {
        attributes[name]
    }

    Enumeration getAttributeNames() {
        Collections.enumeration(attributes.keySet())
    }

    long getCreationTime() {
        0
    }

    long getLastAccessedTime() {
        0
    }

    int getMaxInactiveInterval() {
        0
    }

    ServletContext getServletContext() {
        return Holders.servletContext
    }

    @Deprecated
    String[] getValueNames() {
        [] as String[]
    }

    @Deprecated
    void putValue(String name, Object value) {}

    @Deprecated
    void removeValue(String name) {}

    void invalidate() {}

    boolean isNew() {true}

    void removeAttribute(String name) {
        attributes.remove(name)
    }

    void setAttribute(String name, Object value) {
        attributes[name] = value
    }

    void setMaxInactiveInterval(int arg0) {}
}


And use be like below:


if (HibernateRequestUtils.isBound()) {
    DO YOU CODE IN HTTP REQUEST
}
else {
    HibernateRequestUtils.mock {
        DO YOUR CODE IN MOCK REQUEST AS YOU DO IN REAL REQUEST
    }
}



Using Google Place Autocomplete API in React

I want to have an auto completing location search bar in my react component
Reference Google Maps API JS library via /public/index.html file:
Get google API Key from here -> https://developers.google.com/places/web-service/get-api-key
https://cloud.google.com/console/google/maps-apis/overview
You need to enable Maps JavaScript API & Places Api from below links ->
https://console.developers.google.com/google/maps-apis/apis/maps-backend.googleapis.com

https://console.developers.google.com/google/maps-apis/apis/places-backend.googleapis.com

import React from "react";

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.autocompleteInput = React.createRef();
    this.autocomplete = null;
    this.handlePlaceChanged = this.handlePlaceChanged.bind(this);
  }

  componentDidMount() {
    this.autocomplete = new google.maps.places.Autocomplete(
        this.autocompleteInput.current, {"types": ["geocode"]}
    );

    this.autocomplete.addListener('place_changed', this.handlePlaceChanged);
  }

  handlePlaceChanged(){
    const place = this.autocomplete.getPlace();
    this.props.onPlaceLoaded(place);
  }



  render() {
    return (
        <input ref={this.autocompleteInput}  id="autocomplete" 
         placeholder="Enter your address"
         type="text"></input>
    );
  }
}

export default MyComponent

Wednesday, January 1, 2020

bootstrap-datepicker with React: onChange doesn't fire while onClick does

bootstrap-datepicker with React: onChange doesn't fire while onClick does
import React, { Component } from 'react'
import {Redirect} from "react-router-dom";

class MyComponent extends Component {
    constructor () {
        super();
        this.state = {
     back: false,
            dateOfBirth: "",
            dateOfBirthInput: ""
        };
        this.handleUserInput = this.handleUserInput.bind(this);
    }

    componentDidMount () {
        super.componentDidMount();

        $(this.state.dateOfBirthInput).datepicker({
     format: "mm/dd/yyyy"
 });

        $(this.state.dateOfBirthInput).on('changeDate', function(e) {
            console.log(e);
            console.log(e.target.value);
     this.handleUserInput(e);
        })
    }

    handleUserInput (e) {
        let name = e.target.name;
        let value = e.target.value;

        console.log(`Name=${name}, value=${value}`);

        this.setState({[name]: value});
    }

    render () {
        if (this.state.back) {
            return <Redirect to={'/dashboard/user-profile'} push={true}/>
        }
        return (
            <div>
                <div className="form-group row">
                    <label className={'col-12 col-sm-12 col-md-4 col-lg-3 col-xl-2 col-form-label'}>Date of birth</label>
                    <div className="col-12 col-sm-12 col-md-8 col-lg-9 col-xl-10">
                        <div className='input-group date'>
                            <input name={'dateOfBirth'} value={this.state.dateOfBirth}
                                   onChange={(e) => this.handleUserInput(e)}
                                   ref={(n) => this.state.dateOfBirthInput = n}
                                   type='text' className="form-control"/>
                        </div>
                    </div>
                </div>
            </div>
        )
    }
}

export default MyComponent

Saturday, December 28, 2019

Implementing Programically Redirect With React Router | React redirect to component | Redirect with React Router

A lot of these short blog posts are just for me to find later when I forget how to do something.
So, there is an span where there is a click event named goToAnotherPage, when clicked I just set state the edit variable true, and it redirect to another page using react component named Redirect as described in function goToAnotherPage.
import React, { Component } from 'react'
import {Redirect} from 'react-router-dom'

class SomePage extends Component {
    constructor () {
        super();
        this.state = {
            edit: false
        };
        this.goToAnotherPage = this.goToAnotherPage.bind(this);
    }

    componentDidMount () {
        super.componentDidMount();
    }

    goToAnotherPage(e) {
        this.setState({'edit': true});
    }

    render () {
        if (this.state.edit) {
            return <Redirect to={'/go-to-another-page'} push={true}/>
        }
        return (
            <span onClick={(e) => this.goToAnotherPage(e)}>Go to another page</span>
        )
    }
}

export default SomePage