Wednesday, July 3, 2019

Hooks


  • useEffect
  • useSelector
  • useDispatch
  • useReducer


Example : #1
import React, { Component } from 'react';

class App extends Component {
  constructor(props) {
    super(props)
    this.state = {
      email: '',
      password: ''
    }
  }


  handleEmailChange = (e) => {
    this.setState({ email: e.target.value });
  }
  handlePasswordChange = (e) => {
    this.setState({ password: e.target.value });
  }
  handleLogin=()=>{
    console.log("EMail: " + this.state.email);
    console.log("Password: " + this.state.password);
  }
  render() {
  return (
    <form>
      <input type="text"  placeholder="Email" value={this.state.email} onChange={this.handleEmailChange} />
      <input type="password"  placeholder="Password" value={this.state.password} onChange={this.handlePasswordChange} />
      <button type="button" onClick={this.handleLogin}>Login</button>
    </form>
    );
}

}
export default App
..........................................................................................................................................................................................................
Redux Form

yarn add redux  react-redux redux-form

Step # 1: src/login/Login.js

import React from 'react'
import { Field, reduxForm } from 'redux-form'

const onSubmit = (values) => {
    console.log(values)
}

const LoginForm = (props) => {
    const { handleSubmit, pristine, reset, submitting } = props
    return (
        <div>
            <h2> Login Form</h2>
            <form >
                <div>
                    <label> First Name</label>
                    <Field
                        name='First name'
                        component='input'
                        type='text'
                        placeholder='First name'
                    />
                </div>
                <div>
                    <label>Last Name</label>
                    <Field
                        name='Last name'
                        component='input'
                        type='text'
                        placeholder='Last name'
                    />
                </div>
                <button type='submit' onClick={handleSubmit(onSubmit)} disabled={pristine || submitting}>Submit</button>
                <button type='submit' onClick={reset} disabled={pristine || submitting}>Clear</button>
            </form>
        </div>
    )
}

export default reduxForm({
    form: 'simple'
})(LoginForm)
............................................................................................................................................................................................................

Step # 2: src/App.js

import React from 'react'
import { Provider } from 'react-redux'
import { createStore, combineReducers } from 'redux'
import { reducer as formReducer }from 'redux-form'
import Form from './login/Login'

const Root = combineReducers({
form : formReducer
})

const store  = createStore(Root)
const App =()=>{
  return(
    <Provider store={store}>
<Form/>
    </Provider>
  )
}
export default App

.....................................................................................................................................................................................................................................

Example : #2 [ Input State Change]

constants/Types.js

export const FAVORITE_ANIMAL ='FAVORITE_ANIMAL'
......................................................................................................................................................................................................................................
actions/actionCreators.js
import { FAVORITE_ANIMAL } from '../constants/Types'

 export const setFavoriteAnimal = (value) => {
    return {
        type: FAVORITE_ANIMAL,
        payload: value,
    };

}
......................................................................................................................................................................................................................................
reducer/reducer.js

import { FAVORITE_ANIMAL } from '../constants/Types'

const initialState = {
    favoriteAnimal: "Lions",
};

const reducer = (state = initialState, action) => {
    switch (action.type) {
        case FAVORITE_ANIMAL:
            return {
                ...state,
                favoriteAnimal: action.payload
            };
        default:
            return state;
    }
};
export default reducer
.....................................................................................................................................................................................................................................
components/Home.js

import React, { Component } from 'react'
import { connect } from 'react-redux'
import { setFavoriteAnimal } from '../actions/actionCreators'

class Home extends Component {
    constructor(props){
        super(props)
        this.state={
            favorite: this.props.favoriteAnimal_State
        }
    }
    onSetFavoriteAnimalPress = () => {
        this.props.setFavoriteAnimal_Dispatch(this.state.favorite);
        console.log(this.state)
      }
    render() {
        return (
            <div>
            <h2>{this.props.favoriteAnimal_State}</h2>
            <input onChange ={(text)=>this.setState({favorite:text.target.value})}/>
            <button onClick={this.onSetFavoriteAnimalPress} >Submit</button>
            </div>
        )
    }
}
const mapStateToProps = (state) => {
    return {
      favoriteAnimal_State: state.nav.favoriteAnimal,
    };
  }
  
  const mapDispatchToProps = (dispatch) => {
    return { 
      setFavoriteAnimal_Dispatch: (text) =>  dispatch(setFavoriteAnimal(text)) 
    };
  }

export default connect(mapStateToProps, mapDispatchToProps)(Home)

......................................................................................................................................................................................................................................
App.js
import React, { Component } from 'react'
import { Provider } from 'react-redux'
import { createStore, combineReducers } from 'redux'
import reducer from './reducers/reducer'
import Home from './components/Home'

const Allreducers = combineReducers({
    nav: reducer
})
const store = createStore(Allreducers)


class App extends Component {
    render() {
        return (
            <Provider store={store}>
                <Home />
            </Provider>
        )
    }
}

export default App
......................................................................................................................................................................................................................................






......................................................................................................................................................................................................................................



import React, { Component } from 'react'

const handleChange = (e) => {
 // e.preventDefault()
  console.log(e.target['id'].value)
  alert(e.target['id'].value)
}

const DemoForm = () => {
  return (
    <div>
      <h2> LogIn Form</h2>
      <form onSubmit={handleChange}>
        <input
          type="text"
          name='name'
          id='id'
        />
        <button type='submit'> submit</button>
      </form>
    </div>
  )
}
export default DemoForm
..............................................................................................................................................................................................................
Using Hooks

import React, { useState } from 'react'

const App = () => {
  const [name, setName] = useState('')

  const handleInputChange = (e) => {
    e.preventDefault()
    console.log(`valuw: ${name}`)
  }

  const changeInput=(e)=>{
    setName(e.target.value)
  }
  return (
    <div>
      <form onSubmit={handleInputChange}>
        <input
          type='text'
          value={name}
          onChange={changeInput}
        //  onChange={(e) => setName(e.target.value)}
        />
        <button type='submit'>Submit</button>
      </form>
    </div>

  )
}
export default App

..........................................................................................................................................................................................................................
Multiple Inputs [hooks]

import React, { useState } from 'react'

const Home = () => {
  const [name, setName] = useState({ email: '', password: '' })

  // const _onChangeHandle = (event) => {
  //   setName({...name, [event.target.name]:event.target.value})
  // }

  const _onChangeHandle = (event) => {
    const value = event.target.value;
    setName({...name, [event.target.name]:value})
  }

  const _onSubmit = (e) => {
    e.preventDefault()
    console.log(name)

  }

  return (
    <div>
      <form onSubmit={_onSubmit}>
        <input
          placeholder='Enter Email'
          name='email'
          value={name.email}
          onChange={ _onChangeHandle}
        /><br></br>
        <input
          placeholder='Enter password'
          name='password'
          value={name.password}
          onChange={_onChangeHandle}
        /><br></br>
        <button type='submit' >Submit</button>
      </form>
    </div>

  )
}
export default Home

Happy coding :)
..........................................................................................................................................................................................................................
import React, { useState } from "react";

const App = () => {
  const [state, setState] = useState({
    firstName: "",
    lastName: ""
  })

  const handleChange = (event) => {
    const value = event.target.value;
    setState({
      ...state,
      [event.target.name]: value
    });
  }


  const onSubmit = (e) => {
    e.preventDefault();
    console.log(state)
  }


  return (
    <form onSubmit={onSubmit}>
      <label>
        First name
        <input
          type="text"
          name="firstName"
          value={state.firstName}
          onChange={handleChange}
        />
      </label>
      <label>
        Last name
        <input
          type="text"
          name="lastName"
          value={state.lastName}
          onChange={handleChange}
        />
      </label>
      <button type='submit'>Submit</button>
    </form>
  );
}


export default App

...................................................................................................................................................................................................................................
useReducer with counter Example

import React, { useReducer } from 'react'

const App = () => {
  //const [count, dispatch] = useReducer((state, action) => {
    const [count, dispatch] = useReducer((state, {type, payload}) => {

    switch (type) {
      case 'ADD':
        return state + 1
      case 'SUB':
        return state - 1
      default:
        return state;
    }
  },10);



  return (
    <div>
      <h1>{count}</h1>
      <button onClick={() => dispatch({type:'ADD'})}>Increment</button>
      <button onClick={() => dispatch({type:'SUB'})}>Increment</button>
    </div>
  )
}

export default App

Happy coding :)
..........................................................................................................................................................................................................................
import React, { useReducer } from 'react'

const App = () => {
  const [count, dispatch] = useReducer((state, action) => {
console.log(action)
    switch (action.type) {
      case 'ADD':
        return state + 1
      case 'SUB':
        return state - 1
      default:
        return state
    }
  }, 10)
  return (
    <div>

  <h1>{count}</h1>
      <button onClick={() => dispatch({type:'ADD'})}>Increment</button>
      <button onClick={() => dispatch({type: 'SUB'})}> Dcrement</button>


    </div>

  )
}

export default App


Happy coding :)
..........................................................................................................................................................................................................................
useReducer with REMOVE INDEX

import React, { useReducer, useRef } from 'react'

const App = () => {
  const inputRef = useRef();
  const [items, dispatch] = useReducer((state, action) => {
    switch (action.type) {
      case 'ADD':
        return [
          ...state,
          {
            id: state.length,
            name: action.name
          }
        ]
      case 'REMOVE':
        return state.filter((_, index) => index != action.index)

      default:
        return state
    }

  }, [])

  const _onSubmit = (event) => {
    event.preventDefault();
    dispatch({
      type: 'ADD',
      name: inputRef.current.value
    });
    inputRef.current.value = ''   // Clean the Input Field
  }
  return (
    <>
      <form onSubmit={_onSubmit}>
        <input ref={inputRef} />
      </form>

      <ul>
        {items.map((item, index) =>
          <li key={item.id}>{item.name}
            <button onClick={() => dispatch({ type: 'REMOVE', index })}>X</button>
          </li>
        )}
      </ul>
    </>
  )
}
export default App



Happy coding :)
..........................................................................................................................................................................................................................
useReducer

import React, { useReducer } from 'react'

const reducer = (state, action) => {
  switch (action.type) {
    case 'ADD':
      return state + 1
    case 'SUB':
      return state - 1
    default:
      return state
  }

}

const App = () => {
  const [count, dispatch]=useReducer(reducer, 0)
  return (
    <>
<h1>{count}</h1>
    <button onClick={()=>dispatch({type:'ADD'})}>Increment</button>
    <button onClick={()=>dispatch({type:'SUB'})}>Decrement</button>
    </>

  )

}
export default App

Happy coding :)
..........................................................................................................................................................................................................................
useReducer (simple state & action)

import React, { useReducer } from 'react'

const initialState = 0
const reducer = (state, action) => {
  switch (action.type) {
    case 'ADD':
      return state + 1
    case 'SUB':
      return state - 1
    case 'RESET':
      return initialState
    default:
      return state
  }

}

const App = () => {
  const [count, dispatch] = useReducer(reducer, initialState)
  return (
    <>
<h1>{count}</h1>
      <button onClick={() =>dispatch({type:'ADD'})}>Increment</button>
      <button onClick={() =>dispatch({type:'SUB'})}>Decrement</button>
      <button onClick={() =>dispatch({type:'RESET'})}>Reset</button>
    </>
  )
}

export default App

Happy coding :)
..........................................................................................................................................................................................................................
New Redux - the hooks way


src\reducers\rootReducer.js
const initialState = {
    counter: 0
}
const rootReducer = (state = initialState, action) => {
    switch (action.type) {
        case 'ADD':
            return {
                ...state,
                 counter: state.counter + 1 }
        case 'SUB':
            return {
                ...state,
                counter: state.counter - 1 }
        default:
            return state
    }
}
export default rootReducer

App.js

import React from 'react'
import { Provider, useDispatch, useSelector, useStore } from 'react-redux'
import { createStore } from 'redux'

import rootReducer from './reducers/rootReducer'

const Home = () => {
  const counter = useSelector(state => state.counter)
  const dispatch = useDispatch();
  return (
    <>
      <h1>Hello : {counter}</h1>
      <button onClick={() => dispatch({ type: 'ADD' })}> Increment </button>
      <button onClick={() => dispatch({ type: 'SUB' })}> Decrement </button>
    </>
  )
}
const store = createStore(rootReducer)
const App = () => {
  return (
    <Provider store={store}>
      <Home />
    </Provider>
  )
}
export default App

Happy coding :)
..........................................................................................................................................................................................................................
Fetching data

import React, { useState, useEffect } from 'react'
import axios from 'axios'

const App = () => {
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState('')
  const [post, setPost] = useState({})

useEffect(()=>{
  axios.get('https://jsonplaceholde=r.typicode.com/posts/1')
  .then(res=>{
    setLoading(false)
    setError('')
    setPost(res.data)
  })
  .catch(error=>{
    setLoading(false)
    setPost({})
    setError('Something went wrong')
  })
},[])
  return (
    <>
    {loading ? 'loading.....' : post.title}
    {error ? error: null}
    </>
  )
}
export default App
Happy coding :)
..........................................................................................................................................................................................................................
useReducer

import React, { useReducer, useEffect } from 'react'
import axios from 'axios'

const initialState = {
  loading: true,
  post: {},
  error: ''
}
const reducer = (state = initialState, action) => {
  switch (action.type) {
    case 'FETCH_DATA_SUCCESS':
      return {
        ...state,
        loading: false,
        post: action.payload,
        error: ''
      }
    case 'FETCH_ERROR':
      return {
        ...state,
        loading: false,
        post: {},
        error: 'Something Went wrong!'
      }
    default:
      return state
  }
}

const Home = () => {
  const [state, dispatch] = useReducer(reducer, initialState)
  useEffect(() => {
    axios.get('https://jsonplaceholder.typicode.com/posts/1')
      .then(response =>
        dispatch({
          type: 'FETCH_DATA_SUCCESS',
          payload: response.data
        })
      )
      .catch(error => {
        dispatch({
          type: 'FETCH_ERROR',
        })
      })
  })
  return (
    <>
      {state.loading ? 'loading' : state.post.title}
      {state.error ? state.error : null}
    </>
  )
}

const App = () => {
  return (
    <>
      <Home />
    </>
  )

}
export default App

Happy coding :)
..........................................................................................................................................................................................................................

import React, { useReducer, useEffect, } from 'react'
import { useDispatch, useSelector, Provider } from 'react-redux'
import { createStore } from 'redux'
import axios from 'axios'

const initialState = {
  loading: true,
  post: {},
  error: ''
}



const reducer = (state = initialState, action) => {
  switch (action.type) {
    case 'FETCH_DATA_SUCCESS':
      return {
        ...state,
        loading: false,
        post: action.payload,
        error: ''
      }
    case 'FETCH_ERROR':
      return {
        ...state,
        loading: false,
        post: {},
        error: 'Something Went wrong!'
      }
    default:
      return state
  }
}


const Home = () => {
  const state = useSelector(state => state)
  //const [state,] = useReducer(reducer, initialState)
  const dispatch = useDispatch()
  useEffect(() => {
    axios.get('https://jsonplaceholder.typicode.com/posts/1')
      .then(response =>
        dispatch({
          type: 'FETCH_DATA_SUCCESS',
          payload: response.data
        })
      )
      .catch(error => {
        dispatch({
          type: 'FETCH_ERROR',

        })
      })

  })
  return (
    <>
      {state.loading ? 'loading' : state.post.title}
      {state.error ? state.error : null}
    </>
  )
}
const store = createStore(reducer)
const App = () => {
  return (
    <>
      <Provider store={store}>
        <Home />
      </Provider>


    </>
  )

}
export default App

Happy coding :)
..........................................................................................................................................................................................................................

import React, { useReducer, useEffect } from 'react'
import { useDispatch, useSelector, Provider } from 'react-redux'
import axios from 'axios'
import { createStore } from 'redux'


const initialState = {
  loading: true,
  data: [],
  error: ''
}
const reducer = (state = initialState, action) => {
  switch (action.type) {
    case 'FETCH_DATA':
      return {
        ...state,
        loading: false,
        data: action.payload,
        error: ''
      }
    case 'FETCH_ERROR':
      return {
        ...state,
        loading: false,
        data: [],
        error: 'Something went wrong!'
      }
    default:
      return state
  }

}




const Home = () => {
  const state = useSelector(state => state)
  const dispatch = useDispatch()
  //const [state, dispatch] = useReducer(reducer, initialState)
  useEffect(() => {
    // axios.get('https://jsonplaceholder.typicode.com/todos/1')
    axios.get('https://jsonplaceholder.typicod.com/users')
      .then(res =>
        dispatch({
          type: 'FETCH_DATA',
          payload: res.data
        })
      )
      .catch(error => {
        dispatch({
          type: 'FETCH_ERROR',

        })

      })
  },[])
  return (
    <>
      {state.loading ? 'Loading...' : state.data.map((item) => <h6>{item.name}</h6>)}
      {state.error ? state.error : null}
    </>
  )

}

const store = createStore(reducer)
const App = () => {
  return (
    <Provider store={store}>
      <Home />
    </Provider>

  )
}
export default App

Happy coding :)
..........................................................................................................................................................................................................................
reducer + thunk

import React, { useEffect, useReducer } from 'react'
import { useDispatch, useSelector, Provider } from 'react-redux'
import { createStore, applyMiddleware, compose } from 'redux'
import axios from 'axios'
import thunk from 'redux-thunk'
const initialState = {
  loading: true,
  data: [],
  error: ''
}

const reducer = (state = initialState, action) => {
  switch (action.type) {
    case 'FETCH_API':
      return {
        ...state,
        loading: false,
        data: action.payload,
        error: ''
      }
    case 'FETCH_ERROR':
      return {
        ...state,
        loading: false,
        data: [],
        error: 'Something went wrong!'
      }
    default:
      return state
  }
}
const Home = () => {
  //const [state, dispatch] = useReducer(reducer, initialState)
  const state = useSelector(state => state)
  const dispatch = useDispatch()
  useEffect(() => {
    axios.get('https://jsonplaceholder.typicode.com/users')
      .then(response =>
        dispatch({
          type: 'FETCH_API',
          payload: response.data
        })
      )
      .catch(error => {
        dispatch({
          type: 'FETCH_ERROR'
        })
      })
  })

  return (
    <>
      {state.loading ? 'Loading...' : state.data.map((item) => <h3>{item.name}</h3>)}
      {state.error ? state.error : null}
    </>
  )
}
const middleware =[thunk]
const composeEnhancers= window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose

const store = createStore(reducer, composeEnhancers(applyMiddleware(...middleware)))
const App = () => {
  return (
    <Provider store={store}>
      <Home />
    </Provider>


  )
}
export default App


Happy coding :)
..........................................................................................................................................................................................................................
useReducer

import React, { useReducer } from 'react'
import { createStore } from 'redux'
import { Provider, connect } from 'react-redux'


const initialState = {
  count: 0
}
const reducer = (state = initialState, action) => {
  switch (action.type) {
    case 'ADD':
      return {
        ...state,
        count: state.count + 1
      }
    case 'RESET': {
      return initialState
    }
    default:
      return state
  }
}
const Home = () => {
  const [count, dispatch] = useReducer(reducer, initialState)
  return (
    <div>
      <h1>{count.count}</h1>
      <button onClick={() => dispatch({ type: 'ADD' })}>Increment</button>
      <button onClick={() => dispatch({ type: 'RESET' })}>Reset</button>
    </div>

  )
}


const store = createStore(reducer)
const App = () => {
  return (
    <Provider store={store}>
      <Home />
    </Provider>

  )
}
export default App






Happy coding :)
..........................................................................................................................................................................................................................
useSelector useDispatch

import React, { useReducer } from 'react'
import { createStore, } from 'redux'
import { Provider, connect, useDispatch, useSelector } from 'react-redux'


const initialState = {
  count: 0
}
const reducer = (state = initialState, action) => {
  switch (action.type) {
    case 'ADD':
      return {
        ...state,
        count: state.count + 1
      }
    case 'RESET': {
      return initialState
    }
    default:
      return state
  }
}
const Home = () => {
  const state = useSelector(state => state)
  const dispatch = useDispatch()
  return (
    <div>
     <h1>{state.count}</h1>
      <button onClick={() => dispatch({ type: 'ADD' })}>Increment</button>
      <button onClick={() => dispatch({ type: 'RESET' })}>Reset</button>
    </div>
  )
}
const store = createStore(reducer)
const App = () => {
  return (
    <Provider store={store}>
      <Home />
    </Provider>
  )
}
export default App



Happy coding :)
..........................................................................................................................................................................................................................
useReducer + no more state

import React, { useReducer } from 'react'
import { createStore, } from 'redux'
import { Provider, connect, useDispatch, useSelector } from 'react-redux'


const initialState = {
  count: 0
}
const reducer = (state = initialState, action) => {
  switch (action.type) {
    case 'ADD':
      return {
        ...state,
        count: state.count + 1
      }
    case 'RESET': {
      return initialState
    }
    default:
      return state
  }
}
const Home = () => {
  const [state, dispatch] = useReducer(reducer, initialState)
  return (
    <div>
     <h1>{state.count}</h1>
      <button onClick={() => dispatch({ type: 'ADD' })}>Increment</button>
      <button onClick={() => dispatch({ type: 'RESET' })}>Reset</button>
    </div>
  )
}
const App = () => {
  return (
      <Home />
  )
}
export default App

Happy Coding :)
..........................................................................................................................................................................................................................
Creating Simple React Custom Hook


Let's create a simple Custom React Hook:

The main intent of Custom Hooks are:

  • Separate Logic from User Interface
  • Create Re-usable Logical Block
  • Provide Cleaner and Scalable Code
  • React Custom Hooks can use Other Hooks
  • The custom hook use “useState” hook internally



function useCustomHooks() {
  let userName = "Sapan ";
  let userDesignation = "React";
  return [userName, userDesignation];
}

The above code represents a simple Custom Hooks that return multiple values from it.
 Following need to be taken note of in the above code:
  1. 'use' appended to function name representing Custom Hooks
  2. The Custom Hook above is returning some values
  3. The Custom Hook can then be Re-used
Code                            
import React from 'react'

const useCustomHooks = () => {
  let userName = "Sapan ";
  let userDesignation = "React";

  return [userName, userDesignation];
}

const App=() =>{
  const [name, designation] = useCustomHooks();
  return (
    <div>
      <h1>User Name: {name}</h1>
      <h2>User Designation: {designation}</h2>
    </div>
   )
}
export default App

Passing Parameter to React Hooks
import React from 'react'

const useCustomHooks =(userName, userDesignation) => {
  let Name = "User Name: " + userName;
  let Designation = "User Designation: " + userDesignation;
  return [Name, Designation];
}

const App = () =>{
  const [name, designation] = useCustomHooks("Sapan", "React");
  return (
    <div>
      <h1>{name}</h1>
      <h2>{designation}</h2>
    </div>
   )
}
export default App


Using “useEffect” Hook in React Custom Hooks

function useEmployeeCountHooks() {
  let [empCount, setEmpCount] = useState(0);
  useEffect(() => {
    setTimeout(() => {
      setEmpCount(employeeData.length);
    }, 2000);
  });

  return [empCount];
}

function ApplicationComponent() {
  const [empCount] = useEmployeeCountHooks();
  return (
    <div>
      <h3>"useEmployeeCountHooks" used to maintain App state</h3>
      <b>"useEffect" Hook can be used inside Custom Hooks</b><br /><br />
      <b>"useEffect" is extracting data asynchronously from the aplication</b><br /><br />
      <b>The Custom Component is maintaining the state data as well..</b><br /><br />
      <b>View for the application has been simplified to cater rendering logic</b>
      <h1>Employee Count: {empCount}</h1>
    </div>
  );
}

The benefit offered from the above code are:

  • 'ApplicationComponent' is not responsible for managing 'empCount'
  • Reduces the complexity of View Component 'ApplicationComponent'
  • Custom Hook created is re-usable
  • Business logic has been extracted away from the View Component


Closure:
Create Custom Hooks to reduce the complexity of the View Components. Hooks are an amazing addition to React and must be learned, understood and used.





Happy Coding :)
..........................................................................................................................................................................................................................
CLEAN CODE




Happy Coding :)
..........................................................................................................................................................................................................................



Happy Coding :)
..........................................................................................................................................................................................................................



Happy Coding :)
..........................................................................................................................................................................................................................


Happy Coding :)
..........................................................................................................................................................................................................................


Happy Coding :)
..........................................................................................................................................................................................................................


Happy Coding :)
..........................................................................................................................................................................................................................


Happy Coding :)
..........................................................................................................................................................................................................................


Happy Coding :)
..........................................................................................................................................................................................................................





2 comments: