Mastering the Frontend: Exploring Advanced Techniques and Best Practices in HTML, CSS, JavaScript, and React

Mastering the Frontend: Exploring Advanced Techniques and Best Practices in HTML, CSS, JavaScript, and React

  1. How to implement different lifecycle methods using useEffect?

    How to do this?
    componentDidMount: To mock componentDidMount, use the useEffect hook with an empty dependency array - this will execute the callback function passes as its first parameter, once after the component mounts.
    componentWillUnmount: To mock componentWillUnmount, return a function from the callback function passed as useEffect's first parameter. This returned function will be called when the component unmounts.
    componentDidUpdate: To mock componentDidUpdate, use the 2nd argument to useEffect to set the state or props on which the effect depends on as the dependency array. With that, useEffect's callback method will only be triggered when any of its dependencies changes.

    2 Things to keep in mind while doing so (best practice/pitfalls)
    Specify dependencies: Don't forget to set the dependencies. If not set, the useeffect callback is called after every render of the component unlike lifecycle methods which are only called when the specific lifecycle event occurs .

    Be cautious of infinite loops: If you modify state or props inside the useEffect hook without specifying the correct dependencies, it can cause an infinite loop that will crash your application .

  2. Difference between shallow copy and deep copy

    Intro line
    Often we want to create copies of variables for different purposes. There can be two different kinds of copies created - Shallow copy and Deep copy.

    Shallow copy method creates a copy where the source and the copied variable reference remain the same. This means that modifications made in one place would affect both places.
    Deep copy method creates a copy where the source and the copied variable reference are completely different. This means that modifications made in one place would only affect the variable where we are making a change.

  3. What are callback functions?

    Why is it needed?
    JavaScript is a single-threaded language, which means, it executes the code sequentially one line after another. However, there are some cases in which a part of the code will only run after some lines of code, i.e. it is dependent on another function.
    This is called asynchronous programming. We need callback functions to make sure that a function is only going to get executed after a specific task is completed and not before its completion.
    What is it?
    A callback function in javascript is a function that is passed as an argument in another function. Which is then called inside the parent function to complete a routine or an action.
    How is it used?
    In the case of an event listener, we first listen for a specific event, and if the function detects it, then only the callback function is executed. when a function fetches some data from an API that takes some time to get downloaded.
    We use the callback function here so that the function that needs the data will only get executed when all the required data is downloaded.

  4. How is useReducer different from useState hook?

    Intro line:
    Both useReducer and useState are state management hooks in React which enables functional components to have stateful logic and re-render based on changes to the state.
    3 comparison points: Updating State:

    State Update:
    useState updates the state directly
    useReducer updates state indirectly via a reducer function.
    Syntax: 
    useState returns an array with two elements: the current state value and a function to update it.
    useReducer returns the current state value and a dispatch function to trigger state updates.
    State Complexity: 
    useState is best suited for managing simple state where state changes are isolated and independent of each other.
    useReducer is better suited for managing complex state where multiple state changes are interdependent and need to be handled together.

  5. Grid vs flexbox?

    Intro line:
    CSS Grid and Flexbox are powerful layout systems that provide efficient and flexible ways to design responsive, modular web layouts with ease.
    3 points compared and contrasted: Dimensionality:
    Layout System:
    Grid - 2D layout system, managing both rows and columns simultaneously for complex structures.

    Flexbox - 1D layout model, designed for either row or column alignment, excelling in single-axis scenarios. **
    Content-driven vs. Container-driven:**
    Grid - Container-driven, with a predefined structure and explicit row/column definitions for greater control.
    Flexbox - Content-driven, adjusting to the content size and excelling at aligning and distributing items within a container.
    Use cases:
    Grid - Ideal for larger-scale, grid-based designs with complex layout requirements.

      /* Flexbox wrapper */
     .wrapper {
       display: flex;
     }
    
     /* Grid wrapper */
     .wrapper {
       display: grid;
       grid-template-columns: 2fr 1fr;
       grid-gap: 16px;
     }
    

  6. What are CSS selectors and their types?

    Why is it needed?
    In CSS, selectors are used to target the HTML elements on our web pages that we want to style. There are a wide variety of CSS selectors available, allowing for fine-grained precision when selecting elements to style.
    What is it?
    A CSS selector is the first part of a CSS Rule. It is a pattern of elements and other terms that tell the browser which HTML elements should be selected to have the CSS property values inside the rule applied to them. For example, selecting an element such as h1, or a class such as .special.
    How is it used?
    There are a few different groupings of selectors, and knowing which type of selector you might need will help you to find the right tool for the job. For selecting an element by tag, simply mention the tag's name, for selecting by id use # immediately followed by the name of the id. For selecting by class, use . (dot) immediately followed by the name of the class.Or we can also select based on an attribute by mentioning the tag name followed by the name of the attribute enclosed inside a pair of square brackets.

  7. What is this keyword? What does it point to by default? How does this work for arrow and regular function?

    Why is it needed?
    The primary reason for the introduction of the this keyword in JavaScript was to enable the creation of object-oriented programming constructs in the language. In JavaScript, objects are created using constructor functions or object literals, and the this keyword is used to refer to the current object instance within these constructs.
    In addition to its use in object-oriented programming, the this keyword is also used in other contexts in JavaScript. For example, it can be used to refer to the global object, to bind a function to a specific context, or to create closures.
    What is it?
    i. In JavaScript, the this keyword refers to the current execution context, which could be the global object, the object that a function or method is called on, or a newly created object using the new keyword.
    ii. The value of this is determined at runtime, based on how a function is called or invoked, and it can be different for the same function depending on how it is called.
    - When a function is called a method of an object, this refers to the object that the method is a property of.
    - When a function is called with the new keyword, this refers to the newly created object.
    iii. By default, this refers to the global object (window in the browser, global in Node.js) when it is used outside of any function or object.
    iv. The behavior of this is different in arrow functions compared to regular functions. In arrow functions, this is lexically scoped, which means that it retains the value of this from its enclosing lexical context. In other words, the value of this inside an arrow function is the same as the value of this outside the function.
    For example:
    const person = {
    firstName: "John",
    lastName: "Doe",
    fullName: function() {
    const getFullName = () => {
    return this.firstName + " " + this.lastName;
    }
    return getFullName();
    }
    };
    console.log(person.fullName()); // Output: "John Doe"
    In the example above, the arrow function getFullName uses the this value from its enclosing lexical context, which is the fullName method of the person object. If getFullName had been a regular function, its this value would have been undefined because it is called as a standalone function and not as a method of an object.

  8. Difference between arrow functions and regular functions.

    Intro line:
    Regular functions and arrow functions are two different ways to define functions in JavaScript, each with its own syntax, behavior, and specific use cases in the development process.
    3 points compared and contrasted:
    Syntax:
    Regular Functions - Declared using 'function' keyword, with function name, parameters, and body.

    Arrow Functions - Utilizes fat arrow (=>) notation, with optional parentheses for parameters and concise function body.
    'This' Binding:
    Regular Functions - Own 'this' context, sometimes causing unexpected behavior in event listeners or object methods.

    Arrow Functions - Inherits 'this' from the surrounding scope, ensuring consistent context in callbacks and event handlers.
    Return Type Functionality:
    Regular Functions - Requires an explicit 'return' statement to return a value from the function body, enclosed in curly braces.
    Arrow Functions - Allows for implicit return if the function body is a single expression without the need for the 'return' keyword or enclosing curly braces.

  9. What is Destructuring?

    Need of it:
    Destructuring in JavaScript is needed to streamline the process of extracting values from arrays or properties from objects, ultimately enhancing code conciseness and readability.
    What it is:
    Destructuring is a syntax feature introduced in ES6 that allows extracting values from arrays or properties from objects.
    It can support default values for missing or undefined properties enhancing code reusability and maintainability.
    How it is used:
    i. For Array destructuring: e.g.: let [a, b] = [1, 2]
    Use square brackets [] on the left side of an assignment
    Place variables inside brackets in the desired order
    Assign an array on the right side of an assignment.
    ii. For Object destructuring: e.g.: let {a, b} = {a: 1, b: 2}
    Use curly braces {} on the left side of an assignment.
    Place variable names (property names) inside braces
    Assign an object on the right side of an assignment.

  10. What are higher-order components?

    Need
    i. HOCs were introduced to provide a way to extract common logic and behaviors from components and reuse them across multiple components.
    ii. For example, if you have two components that share similar functionality, you can create a HOC that encapsulates that functionality and use it to wrap both components. This reduces code duplication and makes it easier to update the shared logic in one place.
    What is it?
    i. In React, a Higher-Order Component (HOC) is a function that takes a component as input and returns a new component with extended or modified functionality.
    ii. HOCs allow you to reuse component logic and create more composable and reusable code.
    How is it used?
    i. Define the HOC function that takes a component as input and returns a new component with extended or modified functionality.
    ii. Wrap your existing component with the HOC function, passing it as an argument to the HOC function.
    iii. Render the wrapped component, just like you would with any other component.