React Js (Udemy - John Smilga)
https://www.youtube.com/watch?v=4UZrsTqkcW4&t=38s
What is create-react-app
create-react-app is an npm package that helps to create react apps.
Creating the react apps from scratch can be a long process because we need to
configure it
setup web pack and babel ( that packages our code and transforms it into browser understandable code)
create react app also includes (otherwise we need to configure ) web server
create react app also includes testing library (which we can't easily implement it ourselves).
Hence, create-react-app provides out of box configuration for all the above things.
What is npx?
We will be using npx with create-react-app. The npx is Node Package Runner, it
Downloads the latest version of create-react-app template every time
So it's not dependant on when you last installed create-react-app
In fact, the create-react-app is never installed on our machines, the npx pulls the latest version of create-react-app
npx comes with npm 5.2 or higher
Starting steps after create-react-app
Delete all the files in the src
folder except index.js
How to connect index.js (starting point of the app) with index.html?
index.html will have the code
Our entry point to the app isindex.js
because the goal is to insert index.js
code into the above div placed at index.html.
Notice that the first letter of the function should be captialized. Here Greeting, G is capital.
Also, we must always return something from the function. Otherwise, we get an error.
How to insert the index.js into <div id="root"></div>. That is by using ReactDom.render()
JSX
It's a syntactical sugar to make the elements look like HTML but under the hood, it uses React.createElement(). The syntactic difference between HTML and JSX is, in JSX we use camel case, so for example, onclick
in HTML will be onClick
is JSX. Also, class in HTML will be className in JSX.
React Fragments
The idea of splitting as components
Let's say we have the below code that has a h1 and p. We can split into two componets.
Separate component for p
Practical Tasks
Task 1 : (use state on Array
) Remove List Items on click
Array
) Remove List Items on clickTask 2 : (use state on Object
) Change the message property in the object
Object
) Change the message property in the objectTask 3 : (use State on numbers) - Bad practice as we are not using callback to update state. Good practice is given below
Task 3 : (Good practice) Why to pass a callback function to update the state?
The above counter example (Task 3) is a bad practice. Let's say we have clicked on increase button but the value increases only after 2 seconds. In this two seconds, how many ever times we press the increase button, the value updates only once after 2 seconds. This is because setValue() is asynchronous and when it get's executed, it takes the global value (at the time of execution). This will be 0 and after 2 seconds, when async function, setValue gets executed this will be looking for global value which is 0 and updates to 1. That's the reason it ignores all the clicks.
The best practice is to use a callback function inside the setValue and pass this value as an argument. Now, the value is bound to the function and always updates internally when clicked and will be displayed after 2 seconds.
This above approach of using callbacks to get the value inside of useState can be applied for all 3 tasks above. Some times, when using numbers as state, we definitely need it but in case of array and object useState, it's optional.
UseEffect hook
useEffect runs after every render by default. Every time the state changes the component rerenders and hence the useEffect runs by default.
UseEffect with second argument empty
The useEffect runs only once (first time) when second argument array is empty
UseEffect with dependencies
If we have dependencies in second argument array, then the useEffect runs when that dependency/dependencies change
We can also have multiple useEffects
useEffect with clearnup function
Task 4 : (useEffect) Build a github user profiles page
Task 5: Set Loading Or Error before displaying data
&& and || operators
An alternate way of writing ||
using !
and &&
Problems with Fetch API - Reasons to use axios
We need to call
then
twice (one to getjson
response and the other one is to get the data). That is because the response.json() gives you the promise and not the dataThe second problem is the fetch doesn't return 404 error if the user not found. If you modify the URL, then it doesn't consider 404 as an error. We need to manually write a case to check if we get back the data. The network errors are considered as the errors by fetch API and not 404.
The solution to this problem
React Forms
Controlled Inputs (As I type I change the state)
In controlled inputs, we'll link up our inputs to the state values by using event.target.value
. We don't use useRef hook here
Uncontrolled Inputs
We use useRef for the uncontrolled inputs and not the event.
Advantages of Uncontrolled inputs sometimes
If we want to focus on the search bar right away when the page loads then we can do it using useRef. Of course we can use controlled inputs and then use useRef as well but instead, we can only use useRef to set the state as well like shown above in the image (commented part)
htmlFor
Submit button
We have two options
Either we can add the onSubmit on the form
Or we can add onClick on to the button inside the form and make the button type = submit
Just like in JavaScript, in the form handler method, we get access to event by default
By default, when the form is submitted, it refreshes the page. We need to prevent this by using e.preventDefault()
.
Now, how to access the data inside the inputs
Well, we can set the state values for each input and access them. But when we type something, the state value should be updated using onChange. As and when we type, the state value changes using onChange where the state value gets updated. This is why we call them controlled inputs where the state value is changed based on what we type when onChange is used. onChange is controlling the state updates.
Now that we connected the dots, let's work on a simple task
Task 6: Add form data to an array and display it
Handling multiple inputs
You see we're setting two useStates to two values, one for name and one for age. What if there are multiple inputs like more than 7 or 8 in the form which will generally be the case. We could technically have those many useStates but it would be better if we manage a single useState
using an object.
Finally, we can make use of name attribute in the jsx
Before we see how to handle multiple inputs, let's get to know what name attribute in HTML input tag does
The name
attribute indicates the name of the input. Let's say we have 10 input elements so when we give a unique name to each one, we can then use this later to identify which input we are talking about. The event (in handleSubmit
) will have access to the name using e.target.name
. That's the beauty. Let's now see how we can handle multiple inputs.
useRef hook - Uncontrolled inpyts
In uncontrolled inputs, we'll not link up our inputs to the state values.
Though we could do many things with useRef, the most popular one is to target the dom element and set up uncontrolled input similar to how we do in vanilla JS
useRef
works a lot like useState
but there are a few differences.
Though the useRef and useState
both preserves the values between the renders, the useRef
doesn't cause a re-render like useState
. One of the most use cases of useRef is targeting the dom element.
Think like we are getting back the HTML element on a form submit just like we get when we do document.querySelector(). You can then get the value or whatever. Imagine document.querySelector() is same as useRef current.
useRef
is mostly used to focus on the input element when the page loads
useRef
is mostly used to focus on the input element when the page loadsTask 7 : Focus on input when form loads using useRef
2nd use case of useRef
useRef
To display the previous state value
useReducer hook
Similar to useState
(in fact, the useState
is built on useReducer
) that helps to set the state
and we can use this instead of useState
when the app grows big and we need a certain way to update the state. Consider having many state values that need to change on updating something then this is the way to go. If I click on a button and if 10 individual setState calls must be done then useReducer is better than useState
.
Let's use useReducer to replicate this. Though the useReducer
is not necessary here with such a small number of states, I would like to show how useReducer works.
First define useReducer that takes two args, reducer and intital state
The useReducer will give back state and dispatch (can be any names). Destructure them
Define the arguments of useReducer which are reducer and intitial state
Add, remove operations of useReducer
useContext hook
Used for avoiding props drilling. If intermediate components don't need a specific prop, we some times need to still pass it to that component in order to pass the prop further. We can make use of useContext hook for that
React.createContext() will give access to Provider and Consumer. We earlier used to use Consumer but now we use useContext hook for the consumption of the provided value by Provider.
Provider
Consumer
Setup errors of workspace
The browser page does not auto-refresh after making any changes in the component
To the root path, add .env
file and inside it, add FAST_REFRESH=false
Interesting Articles
Do we need to do event delegation in react?
No, react do performance optimizations for us.
Build and Deploy
Add CI =
Add CI= in package.json
Custom hook
Let's say we have a functionality to fetch the data from an API. So it would have these functionality
Have state value to store the fetched data
An async function to fetch the data from the API and store in the state above
useEffect which calls the function above
So useEffect calls the async function --> async function that gets data from external API and stores in the state.
So the full component would look like this
The data fetch part is this one
This part would be common to fetch the data. Let's say we have to fetch from other API as well. We then need to repeat this above code (variables would be different).
So to keep the code DRY, we can put the above functionality in a function and call that function every time and reuse. But the problem with that is, it would not re render if data changes. So in this case to reuse the functionality and also re render the useEffect hook when data changes, we can use Custom hook.
The difference between a function and custom hook is
Custom hook re-renders any changes just like a useEffect hook
It will start with use keyword
So let's turn the above component to use a custom hook called useFetch(). This useFetch takes a URL parameter so that we can make use of this hook to fetch different APIs. This hook will return the things whatever the main component needs.
The component would now be
This could not be achieved with normal function as we get error if we use hooks inside normal function. But one thing to keep in mind is, if the function name starts with capital letter then hooks can be used inside that function. Then that function will become a react component.
To better understand the difference between normal function and react custom hook, refer this
PropTypes
PropTypes are used when there are some props missing in data we get back from server. Let's say we have https://course-api.com/react-prop-types-example, the last product has missing image and price
If this happens, your entire app will fail and will throw error. Even if 99 products are good and if one product has a missing prop, you will get error and app will not load at all. To counter this, we can use PropTypes and the idea is, if some of the props are missing then we can provide default props.
Now I could have explained this in detail like how we implement it, but since this is very rarely used in the code, I would rather refer to John's video on udemy when needed.
Performance Optimization
React is fast by default. But it still provides some hooks so that we can optimize it further in necessary use cases. These hooks are
React.memo
useMemo
useCallback
Just because react provides these, it doesn't mean you need to use them all over the place. They come with a cost of memory and performance, so absolutely if necessary then only use it. Here's an article that explains when and when not to use it
React Memo
When state or props change in parent, the parent component re-renders. Because of this, even the child component/s re-render which might nor be necessary in some cases.
useCallback
So when count is increased, we didn't want to re-render our child component BigList as the BigList component didn't have count as props. But we do have addToCart function as props in BigList. This function will change every time when count changes as the functions will be re-created when component re-renders hence triggering the child BigList to re-render.
So one reason to use useCallback is to avoid this function (addToCart) re-creation. Once the function doesn't re-create then our react memo will stop re-rendering the child if the parent Index's count value changes.
The second use case of useCallback hook is to address a warning about missing dependencies.
useMemo
useCallback will remember the function (it decides if the function needs to be re-created or not) whereas useMemo is not for a function but for a value. useMemo decides whether a value should be recomputed or not.
React Optimization Summary
Optimization always comes with cost so make sure you see if optimizing makes sense or not in certain scenarios and then only do it.
We have to remember 3 things
React.memo ---> Which renders a component if and only if it's props change
useCallback ---> In react memo, if a function exists as a prop, then that component is re-rendered always even if enclosed with react.memo. This happens because a function is always re-created if the component in which the function is defined changes. To avoid recreation of the function when component re-renders we use useCallback
useMemo ---> useCallback is to stop unnecessary function re-creation whereas useMemo is used to stop unnecessary value re-creation. Let's say if we have a function that returns a value. If we call this function in jsx, whenever the component is re-rendered the function that returns a value is also called. This might take lot of time if function is big. So to avoid unnecessary re-computation of the value (if value computed is same as previous value computed then it should not be recomputed) we use useMemo hook.
Last updated