You must have the latest version of node.js and npm installed on your machine. If it is then you have to run following steps:

  • npm install -g create-react-app
  • npx create-react-app react-demo-app
  • cd react-demo-app
  • yarn start
  • Open your browser at http://localhost:3000

And you will see the running react app on your browser.

NOTE: I have mentioned and tested these steps for ubuntu 18.04. Depending on your OS and its version the steps might be different.

Conceptually, components are like JavaScript functions. They accept arbitrary inputs (called “props”) and return React elements describing what should appear on the screen. Components let you split the UI into independent, reusable pieces, and think about each piece in isolation.

  • Reusability
  • Separation of concerns

Props are arguments passed into React components. Props are like function arguments in JavaScript and attributes in HTML. Props are passed to components via HTML attributes.

For example here we are using props as arguments for the Person component. React components can be treated as functions in javascript:

                    
                      function Person(props) {
                        return(
                          
                            <div className="person-card">
                              <h1 className="person-title">My Name is {props.name}</h1>
                              <p>I am {props.age} years old.</p>
                              <p>I want to learn <span className="persone-course">{props.course}</span></p>
                            </div>
                          
                        )
                      }
                      export default Person;
                    
                  

And by following way we can provide props to a react component:

                    
                      
                        <Person name="Ravi Singh" age="30" course="React Js" />
                      
                    
                  

React components have a built-in state object. The state object is where you store property values that belong to the component. When the state object changes, the component re-renders.

Since state is managed within the components, hence this can be considered as variables declared within a function.

Stateful and stateless components have many different names. They are also known as:

  • Container vs Presentational components
  • Smart vs Dumb components

The literal difference is that one has state, and the other doesn’t. That means the stateful components are keeping track of changing data, while stateless components print out what is given to them via props, or they always render the same thing.

A Key is a special string attribute you need to include when creating lists of elements. Keys help React identify which items have changed, are added, or are removed. Keys should be given to the elements inside the array to give the elements a stable identity.

The best way to pick a key is to use a string that uniquely identifies a list item among its siblings. Most often you would use IDs from your data as keys.

When you don’t have stable IDs for rendered items, we can use the item index as a key as a last resort. But using an item index as keys is not recommended because the order of items may change. This can negatively impact performance and may cause issues with component state.

Hooks are a new introduction from React 16.8. Hooks let you use state and other React features without writing a class.

  • Hooks allow you to reuse stateful logic without changing your component hierarchy.
  • Hooks let you split one component into smaller functions based on what pieces are related (such as setting up a subscription or fetching data).
  • Hooks let you use more of React’s features without classes.

Every React component requires a root element for returning multiple child elements. And this may cause very unstructured DOM.

This is a common pattern in React for a component to return multiple elements. Fragments let you group a list of children without adding extra nodes to the DOM. Look at the following example:

Consider following snippet as return method into App.js

                    
                      return(
                        
                          <div>
                            <SomeComponent />
                          </div>
                        
                      )
                    
                  

Consider following snippet as return method into SomeComponent.js

                    
                      return(
                        
                          <div>
                            <SomeOtherComponent />
                          </div>
                        
                      )
                    
                  

Consider following snippet as return method into SomeOtherComponent.js

                    
                      return(
                        
                          <div>
                            <h1>I am some other component!!</h1>
                          </div>
                        
                      )
                    
                  

Now in DOM the entire code will be reflected as following snippet:

                    
                      
                        <div>
                          <div>
                            <div>
                              <h1>I am some other component!!</h1>
                            </div>
                          </div>
                        </div>
                      
                    
                  

You can clearly see some unuseful sequences of div's. This is the problem. But if we use like:

Consider following snippet as return method into App.js

                    
                      return(
                        
                          <React.Fragment>
                            <SomeComponent />
                          <React.Fragment>
                        
                      )
                    
                  

Consider following snippet as return method into SomeComponent.js

                    
                      return(
                        
                          <React.Fragment>
                            <SomeOtherComponent />
                          </React.Fragment>
                        
                      )
                    
                  

And let the SomeOtherComponent.js remain unchanged. Now the DOM will heve:

                    
                      
                        <div>
                          <h1>I am some other component!!</h1>
                        </div>
                      
                    
                  

This is the advantage of using Fragments in React.

You can understand this by creating a React component which renders a form. In a controlled component, form data is handled by a React component. The alternative is uncontrolled components, where form data is handled by the DOM itself.

Consider the following example:

                    
                      import React, { useState } from "react";

                      const UserForm = (props) => {
                        const [userEmail, setUserEmail] = useState('');
                        const [userName, setUserName] = useState('');

                        render(
                          
                            <React.Fragment>
                              <form>
                                <div className="form-group">
                                  <label>Email: </label>
                                  <input type="email" className="form-control form-control-lg" value={userEmail} />
                                </div>
                                <div className="form-group">
                                  <label>Name: </label>
                                  <input type="text" className="form-control form-control-lg" value={userName} />
                                </div>
                                <div className="form-group">
                                  <button type="submit" className="btn btn-primary btn-lg">Submit</button>
                                </div>
                              </form>
                            </React.Fragment>
                          
                        )
                      }
                    
                  

Suppose this is the component you have and now If you see this component form on browser then try to inspect the form and open your browser console. You will following error:

                    
                      Warning: A component is changing an uncontrolled input to be controlled. This is likely caused by the value changing from undefined to a defined value, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info: https://reactjs.org/link/controlled-components
                    
                  

Here your inputs are uncontrolled because they are using the component's state variables as values but when you write anything in the form fields nothing will change to the state because you have not handlled any change in form field here.

You can remove this error by two ways:

1. Rename all the value attributes as defaultValues. For example:

                      
                        
                          <input type="email" className="form-control form-control-lg" defaultValue={userEmail} />
                        
                      
                    

2. Add some change handlers to handle change in objects when you update the form field values.

                      
                        
                          <input type="email" className="form-control form-control-lg" value={userEmail} onChange={emailChangeHandler} />
                        
                      
                    

and within the component define this emailChangeHandler method:

                      
                        const emailChangeHandler = (event) => {
                          setUserEmail(event.target.value)
                        }
                      
                    

Do the same for name field as well and you will not see this error in browser console. Finally your component should look like this:

                    
                      import React, { useState } from "react";

                      const UserForm = () => {
                        const [userEmail, setUserEmail] = useState('');
                        const [userName, setUserName] = useState('');

                        const emailChangeHandler = (event) => {
                          setUserEmail(event.target.value)
                        }

                        const nameChangeHandler = (event) => {
                          setUserName(event.target.value)
                        }

                        render(
                          
                            <React.Fragment>
                              <form>
                                <div className="form-group">
                                  <label>Email: </label>
                                  <input type="email" className="form-control form-control-lg" value={userEmail} onChange={emailChangeHandler} />
                                </div>
                                <div className="form-group">
                                  <label>Name: </label>
                                  <input type="text" className="form-control form-control-lg" value={userName} onChange={nameChangeHandler} />
                                </div>
                                <div className="form-group">
                                  <button type="submit" className="btn btn-primary btn-lg">Submit</button>
                                </div>
                              </form>
                            </React.Fragment>
                          
                        )
                      }
                    
                  

So here you can check the difference between controlled and uncontrolled components here. First one is uncontrolled component and last one is controlled component.

  • useState causes re-render and value of state should affect on the other hand useRef does not cause re-render.
  • Both useState and useRef remembers their data after a re-render

useState should be used when the value of state should affect what gets rendered. useRef should be used when you want to have a piece of information that persists for the full lifetime of the component - not just during its render cycle.

Example of useState

                    
                      
                        import React, { useState } from 'react';
                        const Contact = () => {

                          const [name, setName] = useState('');
                          const [email, setEmail] = useState('');
                          const [phone, setPhone] = useState('');
                          const [message, setMessage] = useState('');

                          const nameChangeHandler = (event) => {
                            console.log(event.target.value);
                            setName(event.target.value);
                          }

                          const emailChangeHandler = (event) => {
                            console.log(event.target.value);
                            setEmail(event.target.value);
                          }

                          const phoneChangeHandler = (event) => {
                            console.log(event.target.value);
                            setPhone(event.target.value);
                          }

                          const messageChangeHandler = (event) => {
                            console.log(event.target.value);
                            setMessage(event.target.value);
                          }

                          const saveContactData = (event) => {
                            event.preventDefault();
                            const contactUsData = {
                              name: name,
                              email: email,
                              phone: phone,
                              message: message
                            }
                            console.log(contactUsData);
                            setName('');
                            setEmail('');
                            setPhone('');
                            setMessage('');
                          }

                          return(
                            <React.Fragment>
                              <div className="container">
                                <div className="row mt-5 mb-5">
                                  <div className="col-lg-8 col-md-12 col-12 mx-lg-auto">
                                    <div className="card">
                                      <div className="card-body">
                                        <form onSubmit={saveContactData}>
                                          <div className="col-lg-12 mb-4">
                                            <div className="form-group">
                                              <label>Name: </label>
                                              <input type="text" className="form-control form-control-lg" value={name} onChange={nameChangeHandler} />
                                            </div>
                                          </div>

                                          <div className="col-lg-12 mb-4">
                                            <div className="form-group">
                                              <label>Email: </label>
                                              <input type="email" className="form-control form-control-lg" value={email} onChange={emailChangeHandler} />
                                            </div>
                                          </div>

                                          <div className="col-lg-12 mb-4">
                                            <div className="form-group">
                                              <label>Contact: </label>
                                              <input type="text" className="form-control form-control-lg" value={phone} onChange={phoneChangeHandler} />
                                            </div>
                                          </div>

                                          <div className="col-lg-12 mb-4">
                                            <div className="form-group">
                                              <label>Message: </label>
                                              <textarea className="form-control form-control-lg" rows="8" value={message} onChange={messageChangeHandler}></textarea>
                                            </div>
                                          </div>

                                          <div className="col-lg-12 mb-4">
                                            <button type="submit" className="btn btn-primary btn-lg">Submit</button>
                                          </div>

                                        </form>
                                      </div>
                                    </div>
                                  </div>
                                </div>
                              </div>
                            </React.Fragment>
                          ) 
                        }

                        export default Contact;
                      
                    
                  

In the above example every time when you write soemthing in the name, email, contact or message fields you can check in browser console that your component re-rendered.

Example of useRef

                    
                      
                        import React, { useRef } from 'react';

                        const Contact = () => {

                          const email = useRef();
                          const name = useRef();
                          const phone = useRef();
                          const message = useRef();

                          const saveContactData = (event) => {
                            event.preventDefault();
                            const contactUsData = {
                              name: name.current.value,
                              email: email.current.value,
                              phone: phone.current.value,
                              message: message.current.value
                            }
                            console.log(contactUsData);
                            email.current.value = "";
                            name.current.value = "";
                            phone.current.value = "";
                            message.current.value = "";
                          }

                          return(
                            <React.Fragment>
                              <div className="container">
                                <div className="row mt-5 mb-5">
                                  <div className="col-lg-8 col-md-12 col-12 mx-lg-auto">
                                    <div className="card">
                                      <div className="card-body">
                                        <form onSubmit={saveContactData}>
                                          <div className="col-lg-12 mb-4">
                                            <div className="form-group">
                                              <label>Name: </label>
                                              <input type="text" className="form-control form-control-lg" ref={name} />
                                            </div>
                                          </div>

                                          <div className="col-lg-12 mb-4">
                                            <div className="form-group">
                                              <label>Email: </label>
                                              <input type="email" className="form-control form-control-lg" ref={email} />
                                            </div>
                                          </div>

                                          <div className="col-lg-12 mb-4">
                                            <div className="form-group">
                                              <label>Contact: </label>
                                              <input type="text" className="form-control form-control-lg" ref={phone} />
                                            </div>
                                          </div>

                                          <div className="col-lg-12 mb-4">
                                            <div className="form-group">
                                              <label>Message: </label>
                                              <textarea className="form-control form-control-lg" rows="8" ref={message}></textarea>
                                            </div>
                                          </div>

                                          <div className="col-lg-12 mb-4">
                                            <button type="submit" className="btn btn-primary btn-lg">Submit</button>
                                          </div>

                                        </form>
                                      </div>
                                    </div>
                                  </div>
                                </div>
                              </div>
                            </React.Fragment>
                          ) 
                        }

                        export default Contact;
                      
                    
                  

Hope you enjoyed this. Thanks!!!