ReactJS Component life cycle

We can declare special methods on the component class to run some code when a component mounts and unmounts also called lifecycle methods.

A ReactJS component goes through the following phases: initialization, mounting, updating and unmounting.

Create a basic ReactJS App, to follow through the example. You can check this post to get started.

In the example below to check out how these Component methods are called to depict the life cycle, the output for all these methods are logged to the Console.

The constructor initializes the state of the Component. The render method is called after every ComponentWill methods. Once the Component is rendered to the DOM, the ComponentDid method is called.

The componentDidMount() method runs after the component output has been rendered to the DOM.

import React, { Component } from "react";

class TestComponent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      increment: this.props.increment
    };
    console.log(this.state.increment, "Initialized");
  }

  componentWillMount() {
    this.setState({
      increment: this.state.increment = parseInt(this.state.increment) + 1
    });
    console.log(this.state.increment, "Inside ComponentWillMount");
  }

  componentDidMount() {
    this.setState({
      increment: this.state.increment = parseInt(this.state.increment) + 1
    });
    console.log(this.state.increment, "Inside ComponentDidMount");
  }

  componentWillUnmount() {
    this.setState({
      increment: this.state.increment = parseInt(this.state.increment) + 1
    });
    console.log(this.state.increment, "Inside ComponentWillUnmount");
  }

  componentWillUpdate() {
    console.log(this.state.increment, "Inside ComponentWillUpdate");
  }

  componentDidUpdate() {
    console.log(this.state.increment, "Inside ComponentDidUpdate");
  }
  

  render() {
    console.log(this.state.increment, "Render method called");
    return (
      <React.Fragment>
        <div>{this.state.increment} Render method called!</div>
      </React.Fragment>
    );
  }
}

export default TestComponent;
Order of how the Methods were called
DOM output

Whenever the TestComponent component is removed from the DOM, React calls the componentWillUnmount() lifecycle method.

Advertisements

App Pool set idle time out IIS Server

When it comes to managing your website traffic, one of the things to consider is the availability of your website.

IIS has a idle time-out property that is by default set to 20 minutes. This means that if no request comes for your site for 20 minutes of inactivity, IIS would kill the worker process to free-up resources. This means the memory utilised by loading of classes, session etc. This can be helpful when multiple websites may be hosted on the Server and is resource crunched.

You’ll find the below settings under the AppPool advanced settings:

So, when the next request comes to your site to access something e.g. Login page, IIS Server would again need to initialize the Worker process and load the required resources to serve that request. The first request will be slow to respond to the user because of all the initialization time required. You need to think in these terms that how much traffic usually comes to your site. If your website requires high availability, then you should consider setting the idle time-out to 0 in the App Pool settings. Or if high availability isn’t a concern, you can think for how many minutes you’d usually require your application to be available depending on the traffic.

There have been studies regarding the make or break for websites because of their initial load time. So, please be careful about this setting. Internet facing websites usually require high availability. For Intranet websites, you can think of some number of minutes based on the usage.

Change app pool settings iis express

You may face an Asp.Net error while running your Web Application Project in Debug mode using IIS Express:

“an asp.net setting has been detected that does not apply in integrated managed pipeline mode”

This error means that the framework expects the App Pool to be running the Managed Pipeline Mode as Classic. In Classic mode, managed application events are executed by using ISAPI.

There are other ways to suppress the error by making an entry in the Web.Config file to set the validateIntegratedModeConfiguration to false. But it is better to set the correct application pool.

Select your Project under the Solution and press F4 on your keyboard to access the Project Properties as shown below:

Also, you can enable/disable the Authentication for Anonymous and Windows modes.

Check this post on how to create Virtual Directory in IIS Express.

Redux with React JS

Understanding how redux works has been difficult for a beginner like me in general. so I’ve prepared a simple example to build on my other post that uses i18n package to internationalize your SPA using React JS.

This example maintains the state of my previously selected language in Redux store. You can find the completed code here in my Github profile.

Redux is quite an excellent State Managment Framework. I’m using the official react-redux package that takes care of a lot of stuff like one component that wraps your entire app also called higher-order component. This component will subscribe to your store. The rest of your components will be children to this wrapper component and will only get the parts of the state that they need.

You will then have at least one main component that listens to state changes passed down by the Provider from the store. You can specify which parts of the state it should listen to, and those pieces of the state will be passed down as props to that component (and then of course, it can pass those down to its own children). You can specify that by using the connect() function on your Parent level component and using the mapStateToPropsfunction as a first parameter.

The entire state of the Application is represented by a State tree which is read-only. And every time you need to modify the state, you need to dispatch an Action.

Action object structure should always have a type property. Any other custom property can be added.
Type property e.g. “INCREMENT”, “DECREMENT”

Pure functions are predictable. They always give the same output for the same set of arguments.
Impure functions have side-effects. They may make changes to the data with database or network calls.
Redux takes the previous state, dispatches an action and returns the next state as a new object. This function that describes the state mutation is called the reducer.
Reducers expect 2 arguments: state and action.

e.g.
const counter = (state=0, action) => {
	switch(action.type) {
		case 'INCREMENT':
			return state + 1;
		case 'DECREMENT':
			return state - 1;
		default:
			return state;
	}
}

The store binds together the 3 principles of Redux:

  • It holds the applications’s current state object.
  • It lets you dispatch actions.
  • When you create it, you need to specify the reducer that tells you how state is updated with actions.

Below is the code for the store initialization:

import { createStore, applyMiddleware } from 'redux';
import { persistStore, persistReducer } from 'redux-persist';
import storage from 'redux-persist/lib/storage';
import thunk from 'redux-thunk';
import rootReducer from './reducers/index';
import { composeWithDevTools } from 'redux-devtools-extension';
import Immutable from 'immutable';

const persistConfig = {
  key: 'root',
  storage : storage,
}

const persistedReducer = persistReducer(persistConfig, rootReducer);

const initialState = {};

const middleware = [thunk];

const composeEnhancers = composeWithDevTools({
  serialize: {
    immutable: Immutable
  }
});

export const store = createStore(persistedReducer, initialState, composeEnhancers(applyMiddleware(...middleware)));
export const persistor = persistStore(store)

Below is the code for App Component wrapped under the Provider component:

import React, { Component, Suspense } from "react";
import { Route, Switch, BrowserRouter as Router } from "react-router-dom";
import { Provider } from 'react-redux';
import { store, persistor } from '../store';
import { PersistGate } from 'redux-persist/integration/react'
import HomePage from "./home/HomePage";
import AboutPage from "./about/AboutPage";
import Header from "./common/Header";
import PageNotFound from "./PageNotFound";
import CoursesPage from "./courses/CoursesPage";
import '../config/i18n'

export class App extends Component {
  
  render() {
    let data = localStorage.getItem('persist:root') && JSON.parse(JSON.parse(localStorage.getItem('persist:root')).langOptionsReducer).option.value;
    console.log(data)
    console.log(this.props)
    this.props.props.changeLanguage(data)

    return (
      < Provider
        store={store} >
        {/* https://github.com/rt2zz/redux-persist/blob/master/docs/PersistGate.md */}
        < PersistGate
          loading={<div>loading app...</div>}
          // onBeforeLift={onBeforeLift}
          persistor={persistor} >
      <div className="container-fluid">
        <Header />
        <Switch>
          <Route exact path="/" component={HomePage} />
          <Route path="/courses" component={CoursesPage} />
          <Route path="/about" component={AboutPage} />
          <Route component={PageNotFound} />
        </Switch>
      </div>
      </PersistGate >
      </Provider >
    );
  }
}

export default App;

Below is the code for the action method, changeLang that is dispatched when a language option is selected:

export const changeLang = (option)=> (dispatch) => {
    dispatch({type : 'langOptions',
    payload : option})
}

This is the code for the langOptions reducer that is fired by the action method:

const initialState={option:{}}

export default function(state=initialState, action){
    switch (action.type) {
        case 'langOptions':
            return {
                ...state,
                option:action.payload
            }
        default:
            return state
    }
}

All the reducers in your application need to be combined into a single reducer as in the index.js file under the reducers folder:

import { combineReducers } from 'redux';
import langOptionsReducer from './langOptions'

export default combineReducers({
    langOptionsReducer
})

React Redux provides a connect function for you to read values from the Redux store (and re-read the values when the store updates). The connect function takes two arguments, both optional: mapStateToProps : called every time the store state changes. It receives the entire store state, and should return an object of data this component needs. 2nd parameter is mapDispatchToProps which can either be a function or a full object of action creators.

Code for the HomePage with connect function using mapStateToProps argument as below:

import React, { Component } from "react";
import { Link } from "react-router-dom";
//import "../../node_modules/bootstrap/dist/css/bootstrap.css";
import Select from "react-select";
import { options } from "../../config/options";
import "../../config/i18n";
import { withTranslation } from "react-i18next";
import { connect } from "react-redux";
import { changeLang } from "../../actions/langOptions";

export class HomePage extends Component {
  constructor(props) {
    super(props);
    console.log("inside constructor");
    this.state = {
      lang: options[0]
    };
  }

  changeLang = lang => {
    const { i18n } = this.props;
    const { value } = lang;
    this.props.changeLang(lang);
    this.setState({ lang });
    i18n.changeLanguage(value);
  };

  componentWillReceiveProps(props) {
    console.log(props);
  }

  componentDidMount() {
    this.setState({
      lang: this.props.option.value ? this.props.option : options[0]
    });
    // this.props.i18n.changeLanguage(options[2].value);
  }

  render() {
    const { lang } = this.state;
    return (
      <React.Fragment>
        <div className="jumbotron">
          <h1>Courses Administration</h1>
          <Link to="about" className="btn btn-primary btn-lg">
            Learn more
          </Link>
        </div>
        <br />
        <div style={{ width: "200px" }}>
          <Select
            defaultValue={options[0]}
            options={options}
            value={lang}
            onChange={this.changeLang}
            className="App-Select"
          />
        </div>
      </React.Fragment>
    );
  }
}

const mapStateToProps = state => {
  return {
    option: state.langOptionsReducer.option
  };
};

export default connect(
  mapStateToProps,
  { changeLang }
)(withTranslation("translations")(HomePage));

Internationalization with React JS i18n package

Building Single Page Applications (SPA) in React JS that require multi-language support require a way for the user to be able to select the preferred language and all or specific text on the page or site should change.

React supports a package i18next that helps load the default language and save the preferred language which the user selects from the UI. react-i18next is built on top of i18next and is a powerful internationalization framework for React JS. This post explains i18n usage for v10 or above.

This example is built on top of my other post for Client-side routing here.

You can find the i18n demo code in my Github profile here.

You need to install the package react-i18next using npm as below:

npm install i18next
npm install react-i18next

Initialize the i18next store placed under the config folder as below:

import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import en from "../locales/en";
import fr from "../locales/fr";
import it from "../locales/it";
import de from "../locales/de";
import es from "../locales/es";
i18n.use(initReactI18next).init({
  resources: {
    en,
    fr,
    it,
    de,
    es
  },
  fallbackLng: "en",
  debug: true,
  ns: ["translations"],
  defaultNS: "translations",
  keySeparator: false,
  interpolation: {
    escapeValue: false,
    formatSeparator: ","
  },
  react: {
    wait: true
  }
});
export default i18n;

The i18n package has a provider which would wrap your react App component.

import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./components/App";
import * as serviceWorker from "./serviceWorker";
import { BrowserRouter as Router } from "react-router-dom";
import { I18nextProvider } from "react-i18next";
import i18n from "./config/i18n";
import "bootstrap/dist/css/bootstrap.min.css";
ReactDOM.render(
  <I18nextProvider i18n={i18n}>
    <Router>
      <App />
    </Router>
  </I18nextProvider>,
  document.getElementById("root")
);

Maintain your translation files under the Locales folder and make sure the namespace matches the one provided in the i18next store initialization.
Example translation here:

{
  "translations": {
    "title": "<0>Acerca de</0>",
    "intro": "<0>Esta es la página Acerca de.</0>"
  }
}

The text in the About page is translated as below using the locales:

import React from "react";
import { Trans } from "react-i18next";

const AboutPage = () => (
  <div>
    <Trans i18nKey="title">
      <h2>About</h2>
    </Trans>
    <Trans i18nKey="intro">
      <p>This is the About page.</p>
    </Trans>
  </div>
);

export default AboutPage;

The i18nKey matches the specific text to be translated under the namespace.

The HomePage.js code has a drop-down change language event that will change the translation in the About page when selected.

changeLang = lang => {
    const { i18n } = this.props;
    const { value } = lang;
    this.props.changeLang(lang);
    this.setState({ lang });
    i18n.changeLanguage(value);
  };

The app is hosted on IIS Server. Check out the post here on how to host react app on IIS.

There is also a branch in Github here, that explains the i18n legacy version usage i.e. till v9.

SQL Server Instead Of trigger to prevent duplicates

You might face a scenario where you’re using a REST Web Service or WebAPI where multiple hits of the same request to the API from the User interface is causing duplicate inserts. As the hits come to the API at the same date time-stamp, the API check fails at the database level as that record won’t exist in the table at that point in time.

To prevent the duplicate from getting inserted, we have multiple options at the Database level and one of them is using Instead Of trigger.

Using the INSTEAD Of trigger, you can conditionally choose to INSERT into the table or take some other action as per the requirement.

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[PREVENT_DUP_INSERT] ON [dbo].[tbl_submission]
INSTEAD OF INSERT
AS
BEGIN
	SET NOCOUNT OFF;
	IF NOT EXISTS(
		SELECT 1 FROM dbo.tbl_submission
		WHERE question_uid=(SELECT inserted.q_uid FROM inserted)
		AND user_survey_instance_id=(SELECT user_inst_id FROM inserted)
	)
	BEGIN
		INSERT INTO dbo.tbl_submission(user_id,q_uid,[value],[group],user_inst_id,created_at,updated_at)
		SELECT user_id,q_uid,[value],[group],user_inst_id,created_at,updated_at FROM inserted
	END
	SELECT [id] FROM [dbo].[tbl_submission] WHERE @@ROWCOUNT > 0 AND [id] = scope_identity();
END

An id must be returned by the body of the INSTEAD OF trigger. This is required especially if you’re using an ORM like Entity Framework which may be give concurrency related exception.

You can also choose to apply UNIQUE constraint on select columns to prevent duplicates and handle the Insert exceptions in the API or Trigger itself. But in my case, since there are already few duplicate insertions and one of the columns was VARCHAR(MAX) which does not allow creating UNIQUE indexes.

Find word in SQL Server Varchar variable

I’ll be discussing two ways by which you can search for a string in a SQL Server variable:

Using CHARINDEX() Method:

This function is used to return the position of a substring in string. It’ll return 0 if the substring is not found.
This start position value of the word can be useful for other calculations as well.

DECLARE @strWord nvarchar(50)='My Test String'  

IF CHARINDEX('Test String',@strWord) > 0   
   PRINT 'Found'
ELSE  
    PRINT 'Not Found'
	
Output:
Found

Use the Index value in another variable for other calculations with CHARINDEX as below:

DECLARE @iDex INT
SELECT @iDex=CHARINDEX('Test String',@strWord)

Another way is to use the LIKE operator in SQL Server. This operator is also used in SQL queries’ WHERE clause e.g.

SELECT * FROM Tbl_Name WHERE mainStringCol LIKE '%Test String%'

The above query will fetch all rows where the mainStringCol contains the text “Test String”.

Now, to find a string in a Varchar variable using the LIKE operator, e.g. below:

DECLARE @txtMailBody nvarchar(MAX)='  Hello Mr Anderson...'
IF @txtMailBody LIKE '%Hello Mr%'
	PRINT 'Hello'
ELSE IF @txtMailBody LIKE '%Wad Up%'
	PRINT 'Wad Up'
ELSE
	PRINT 'Goof Up!'

Output:
Hello