Wednesday, October 16, 2019

useState

useState

Allows for a component to save data within the component and for its children

A simple counter

create a simple variable through useState with an initial value. Use the components to fiddle with its value

import React, { useState} from 'react';

const CounterPage = ({counter}) => {
  let [count, setCount] = useState(counter)

  const addCounter = (e) => {
    setCount(++count);
    
  }

  const reduceCounter = (e) => {
    setCount(--count);
  }

  return (
    <div className="container">
      <h4>Counter component</h4>
      <p>Count is {count}</p>
      <button class="btn waves-effect waves-light" onClick={addCounter}>
        <i class="material-icons">add</i>
      </button>  
      <button class="btn waves-effect waves-light" onClick={reduceCounter}>
        <i class="material-icons">arrow_downward</i>
      </button>
    </div>
  )
}

export default CounterPage;


Let's do this same counter from an object. It's not that different from above. As you can see from the code below, the only change you may see in the code is the way we update. We use ... (spread operator) to copy over current content and update the variable of our choice.

import React, {useState} from 'react'

const SimpleObjectCounter = () => {
  const init = {counter1: 10, counter2: 10};
  let [complexCounter, setComplexCounter] = useState(init);

  return (
    <div className="container">
      <h2>A little COMPLEX counter</h2>
      <p>We are now dealing with a counter object and not a simple counter variable</p>
      <p>
        Counter 1 - {complexCounter.counter1}<br />
        Counter 2 - {complexCounter.counter2}
      </p>
      <button onClick={e => setComplexCounter(currentState => ({
        ...currentState,
        counter1: currentState.counter1 + 1
      }))}>Increment Counter 1</button>
    </div>
  )
}

export default SimpleObjectCounter


A form with state

This is an extension of what we have above, with HTML form. Whats interesting in this case though is the way we do 2 way update to state. A simple onChange event to update state and set value property of HTML control with data from state. And that's pretty much it

import React, {useState} from "react";

const SimpleForm = () => {
  const formInit = {first_name: '', last_name: ''};
  let [simpleForm, setSimpleForm] = useState(formInit);

  return (
    <div className="row">
      <form className="col s8 offset-m3" onSubmit={(e) => {
        e.preventDefault();
        console.log(simpleForm);
      }}>
        <div className="row">
          <h4>Simple useState for a Form</h4>
          <div className="input-field col s4">
            <input
              placeholder="Placeholder"
              id="first_name"
              type="text"
              value = {simpleForm.first_name}
              className="validate"
              onChange = {e => {
                const value = e.target.value;
                // console.log(value);
                setSimpleForm(currentState => ({
                ...currentState,
                first_name: value
              }))}}
            />
            <label htmlFor="first_name">First Name</label>
          </div>
          <div className="input-field col s4">
            <input id="last_name" type="text" className="validate" onChange = {e => {
              const value = e.target.value;
              // console.log(value);
              setSimpleForm(currentState => ({
              ...currentState,
              last_name: value
            }))}} />
            <label htmlFor="last_name">Last Name</label>
          </div>
        </div>
        <div className="row">
        <div className="col s6">
            <button type="submit">Submit</button>
        </div>
        </div>
      </form>
    </div>
  );
};

export default SimpleForm;

You can also split above state to multiple variables and track them separately too, if that's easier

const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');

Create a custom state hook

Let's move on to another level. Instead of handling all state level items in raw mopde, we could create a custom hook of our own and expose simple functions for operation. Like say from the above example, we could have functions like updateState('FirstName', e.target.value) in onChange event. Easier to follow and re-use too.
Custom react hook is nothing more than a simple JS function that exposes certain functionality and maintains state. This keeps the code clean

import {useState} from 'react'

export const useFormState = initialValues => {
  let [formState, setFormState] = useState(initialValues);
  return [
    formState,
    e => {
      setFormState({...formState, [e.target.name]: e.target.value})
    }
  ];
  
}

How do we use it in our component. Easier than you think, import it and a simple invocation

import React from "react";
import {useFormState} from "./useFormState";

const ReusableFormState = () => {
  const formInit = {email: '', password: ''};
  let [simpleForm, handleFormChange] = useFormState(formInit);

  return (
    <div className="row">
      <form className="col s8 offset-m3" onSubmit={(e) => {
        e.preventDefault();
        console.log(simpleForm);
      }}>
        <div className="row">
          <h4>A Reusable useForm state with React Hooks</h4>
          <div className="input-field col s4">
            <input
              placeholder="EMail ID"
              name="email"
              type="email"
              value = {simpleForm.email}
              className="validate"
              onChange = {handleFormChange}
            />
            <label htmlFor="email">EMail</label>
          </div>
          <div className="input-field col s4">
            <input name="password" type="password" className="validate" 
              onChange = {handleFormChange} />
            <label htmlFor="password">Password</label>
          </div>
        </div>
        <div className="row">
        <div className="col s6">
            <button type="submit">Submit</button>
        </div>
        </div>
      </form>
    </div>
  );
};

export default ReusableFormState;



Together with "useReducer" state hook is a great way to write your code

No comments: