React with Router,AJAX, Redux etc

In this session we will learn

  1. Router
  2. Link & Nav Link
  3. Higher Order Components(HOC)
  4. Programatic Redirects
  5. Axios (Nodejs utility for AJAX)
  6. Route Parameters
  7. Switch Tag to link only exact match
  8. Importing Images
  9. Redux Intro
  10. Integrating with Jquery

Installations Required

For Create React App and React basic stuff

npx create-react-app my-app

For extra utilities in this chapter

npm install react-router-dom
npm install axios
npm install redux react-redux

React Router

video, Git

To use React router, you must install react-router package

npm install react-router-dom

Sample app creates an SPA poketimes with Home, About Us & Contact Page
Steps:

  1. Create a new folder components in src folder
  2. Create components for each page there. Home.js, About.js, Contact.js & Navbar.js
  3. import router classes. see App.js & Navbar.js
    import { Route, BrowserRouter } from 'react-router-dom'
  4. Enclose entire App JSX in <BrowserRouter> tag;
  5. Use <Route> tag to switch to component eg:<Route path='/about' component={About} />.
  6. For home page use exact keyword to avoid home conetents in other pages on top. eg: <Route exact path='/' component={Home}/>

Links & Navlinks

Video

Stop requests to Server

In Navbar.js

  1. import Link, NavLink
    import { Link, NavLink } from 'react-router-dom'
  2. Change <a href= to <Link to=. (PS: 'Link' was imported)
  3. if we use <NavLink to= instead of <Link to=, an additional class active will be added to a tag when clicked

27. Programatic Redirects

When enclosed in <Route> tag, some additional info is send to props, history, location, match(is exact etc), content.
We can use props.history.push('/newURL'); to redirect programatically. eg: props.history.push('/about');

In the case of Navbar, which is not enclosed in <Route> tag, we need to use Higher order component WithRouter. It gives extra properties to props.

Navbar.js

It has to be imported first

import { Link, NavLink, withRouter } from 'react-router-dom'

And then used to wrap in export

export default withRouter(Navbar)

28. More about Higher order components

Video

Git

Higher Order Components are function that wraps components to supercharge them with extra properties and methods

eg: hoc/Rainbow.js

import React from 'react'
const Rainbow = (WrappedComponent) => {
  const colours = ['red', 'pink', 'orange', 'blue', 'green', 'yellow'];
  const randomColour = colours[Math.floor(Math.random() * 6)];
  const className = randomColour + '-text';
  return (props) => (
    <div className={className}>
      <WrappedComponent {...props} />
    </div>  
  )  
}
export default Rainbow

which is used in components/About.js

import Rainbow from '../hoc/Rainbow'

and

export default Rainbow(About)

29. Using Axios

Video

Git

Axios is a Javascript library used to make HTTP requests from node. js or XMLHttpRequests from the browser and it supports the Promise API that is native to JS ES6. It can be used intercept HTTP requests and responses and enables client-side protection against XSRF. It also has the ability to cancel requests. It is isomorphic (= it can run in the browser and nodejs with the same codebase).
On the server-side it uses the native node.js http module, while on the client (browser) it uses XMLHttpRequests.

PS: Instead of Axios, fetch could be used, but this chapter is giving an intro to axios in nodejs.
eg:

fetch('https://jsonplaceholder.typicode.com/posts/')
      .then(response => response.json())
      .then(json => console.log(json))

is same as

axios.get('https://jsonplaceholder.typicode.com/posts/')
      .then(res => {
        console.log(res.data);
       })

To test with react it should be installed with npm

npm install axios

In this test REST API from Free fake API for testing and prototyping. is used.

  1. Import axios import axios from 'axios'.
  2. Use the lifecycle method componentDidMount to fetch data on page load in components/Home.js
componentDidMount(){
    axios.get('https://jsonplaceholder.typicode.com/posts/')
      .then(res => {
        console.log(res);
        this.setState({
          posts: res.data.slice(0,10)
        });
      })
  }

this.setState will force render() , see life cycle
and in in render. Usefull CSS classes from materialize card, card-content,cart-title.

        <div className="post card" key={post.id}>
            <div className="card-content">
              <span className="card-title">{post.title}</span>
              <p>{post.body}</p>
            </div>
          </div>

30. Route Parameters

Extracting variables in url. This is similar to .htaccess

Video 1 ,
Video 2

  1. in App.js ,
    use <Route path='/:post_id' component={Post} /> .Post component is to be created.

  2. Use in <Link to={'/' + post.id} /> in Home.js

  3. Create a new Component Post.js

get post id as follows

componentDidMount(){
    let id = this.props.match.params.post_id;
    this.setState({
      id
    })
  }
  1. To make is look interactive check Home.js & Post.js

32. Switch Tag to link only exact match

Video

As in .htaccess, /:post_id and /contact may be treated similarly. to avoid this there are two options

  1. create unique prefix for dynamic urls eg /posts/:post_id in <Route/> in in App.js and use <Link to={'/posts/' + post.id} /> in Home.js

OR

  1. use <Switch /> tag from react-router-dom (must be imposted first) inside <Navbar> tag in Home.js.
    This ensure that only one of the links in the list of links in <Navbar> will be taken and rest discarded.

33. Importing Images

Video;

  1. Image to be imported must be saved in /src folder
  2. import Pokeball from '../pokeball.png' in Home.js
  3. use as <img src={Pokeball} alt="A Pokeball" />
  4. some changes are made in index.css for this chapter

34. Redux Intro

Video

Redux

  1. Central data store for all app data
  2. Any component can access data from it
  3. Makes state management easy

Redux Process

Process

Redux Process

  1. there is a central store which represents the global state of the application.
  2. there is a Reducer class
  3. Component classes dispatch action , reducer captures it.
  4. Reducer updates central store
  5. props of other components subscribed to it will get updated.

35. Redux Stores

Video

Test with Codepen

Net ninja URL for this chapter is https://codepen.io/MickGe/pen/VweoQJj

  1. Go to JS settings
  2. Set JS Preprocessor as Babel
  3. Set cdnjs url of redux in the tuorial https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.0-rc.1/redux.js Latest we get by searching in the window is 4.2.1
  4. url of codepen redux project is https://codepen.io/osolsolutions/pen/gOjyeMp
  5. change project title as Redux Basics.
  6. click console button at bottom left

Edit JS

Important points

  1. extract createStore from Redux. const { createStore } = Redux;'
  2. create a reducer.myreducer is just a function that interacts with the store. it takes 2 parameters , state and action. action will have a type property. eg: { type: "ADD_TODO", todo: "buy milk" }.
function myreducer(state = initState, action) {

Change in state will be made in reducer depending on type of action.
eg:

if (action.type == 'ADD_TODO') {
    return {
      ...state,
      todos: [...state.todos, action.todo]
    }
  }

This is similar to setState in Component classes. But unlike setState in components, where only required properties is to be set, in reducer all properties must be set. that is why ...state, is prepended.

  1. Create an initial state initState to pass to reducer on page load.
    const initState = {
    todos: [],
    posts: []
    };
  2. create store with redcer as arfgument `const store = createStore(myreducer);
  3. store.dispatch(action)
  4. store.subscribe(, we will get the current state with store.getState().

36. Redux Actions

Video

37. Redux Cont'd

Video

38. Redux Cont'd Part 3

Video

Final code is

const { createStore } = Redux;
const initState = {
  todos: [],
  posts: []
};
function myreducer(state = initState, action) {
  if (action.type == 'ADD_TODO') {
    return {
      ...state,
      todos: [...state.todos, action.todo]
    }
  }
  if (action.type == 'ADD_POST') {
    return {
      ...state,
      posts: [...state.posts, action.post]
    }
  }
};
const store = createStore(myreducer);
store.subscribe(() => {
  console.log('state updated');
  console.log(store.getState());
})
store.dispatch({ type: "ADD_TODO", todo: "buy milk" });
store.dispatch({ type: "ADD_TODO", todo: "sleep some more" });
store.dispatch({ type: "ADD_POST", post: "egg hunt with Yoshi" });

39. Redux Part4 (Using Redux in React)

Video ,
Git

To use in create react app, 2 modules must be installed

  1. redux
  2. react redux(serves as a layer between react and redux)
npm install redux react-redux

Steps to use redux in react

  1. Redux related objects must me imported in index.js
import { createStore } from 'redux'
import { Provider } from 'react-redux'
  1. Provider should wrapp <App />.
ReactDOM.render(<Provider store={store}><App /></Provider>, document.getElementById('root'));
  1. create reducer rootReducer to pass to const store = createStore(rootReducer);

  2. import rootReducerin index.js

40. Using component to interact with redux

Video ,
Git

Component Used is [Home.js](rootReducer

import { connect } from 'react-redux'

In export wrap it in a method that maps the state to props, here state.posts to props.props . state will be available when it is embedded in react-redux.connect(). ie a higher order component is created with connect(mapStateToProps), which is then used to wrap Home , so as to give it an extra power, here give props from state.

The first parameter to connect is similar to store.subscribe( in a non class js ,as in this . it gets central state as argument, where as to get state in store.subscribe, you should use store.getState()

const mapStateToProps = (state) => {
  return {
    posts: state.posts
  }
}
export default connect(mapStateToProps)(Home)

41. Blog Detail Page

Filter from state, the required item send via props

Video
Git

Post.js

const mapStateToProps = (state, ownProps/*props received via tag*/) => {
  let id = ownProps.match.params.post_id;
  return {
    post: state.posts.find(post => post.id === id)
  }
}
export default connect(mapStateToProps)(Post)

42. Map Dispatch to Props

Interact with state in central store. eg: Delete, dispatch event, which is caught by reducer and central state is changed accordingly.

{Video](https://www.youtube.com/watch?v=40pWMVMnftc&list=PL4cUxeGkcC9ij8CfkAY2RAGb-tmkNwQHG&index=42)
Git

Post.js

const mapDispatchToProps = (dispatch) => {
  return {
    deletePost: (id) => dispatch({type: 'DELETE_POST', id: id})
  }
}
export default connect(mapStateToProps, mapDispatchToProps)(Post)

The second parameter to connect receive store.dispatch as its argument

In render

        <div className="center">
          <button className="btn grey" onClick={this.handleClick}>
            Delete Post
          </button>
        </div>

and add the method handleClick

handleClick = () => {
    this.props.deletePost(this.props.post.id);
    this.props.history.push('/');
  }

anin in rootReducer

const rootReducer = (state = initState, action) => {
  console.log(action);
  if(action.type === 'DELETE_POST'){
   let newPosts = state.posts.filter(post => {
     return post.id !== action.id
   });
   return {
     ...state,
     posts: newPosts
   }
  }
  return state;
}

43 Action Creaters

Action creators are used to seperate code , so as to make exclusive class/function that handles dispatch event. so the code is more organised.

Video,
Git

Action creater used in this project is actions/postActions.js

export const deletePost = (id) => {
  return {
    type: 'DELETE_POST',
    id
  }
}

and in

Post.js

import { deletePost } from '../actions/postActions'

and

const mapDispatchToProps = (dispatch) => {
  return {
    deletePost: (id) => dispatch(deletePost(id))
  }
}

44. Wrapup and next steps

Video

New Play list of React, Redux and Firebase App , 40 videos