React Concepts coding - rs-hash/Senior GitHub Wiki

1. Create a class component with state and lifecycle methods.

Here's an example of a class component in React that includes state and lifecycle methods:

import React, { Component } from 'react';

class ClassComponent extends Component {
  constructor(props) {
    super(props);

    // Initialize state
    this.state = {
      count: 0,
    };
  }

  // Lifecycle method: componentDidMount
  componentDidMount() {
    console.log('Component is mounted.');
  }

  // Lifecycle method: componentDidUpdate
  componentDidUpdate(prevProps, prevState) {
    console.log('Component updated.');
    console.log('Previous state:', prevState);
    console.log('Current state:', this.state);
  }

  // Lifecycle method: componentWillUnmount
  componentWillUnmount() {
    console.log('Component will unmount.');
  }

  // Custom method to increment the count
  incrementCount = () => {
    this.setState((prevState) => ({
      count: prevState.count + 1,
    }));
  };

  render() {
    return (
      <div>
        <h1>Class Component with State and Lifecycle Methods</h1>
        <p>Count: {this.state.count}</p>
        <button onClick={this.incrementCount}>Increment</button>
      </div>
    );
  }
}

export default ClassComponent;

In this class component:

  • We create a class ClassComponent that extends Component, the base class for class components in React.

  • In the constructor, we initialize the component's state with an initial count of 0.

  • We implement several lifecycle methods:

    • componentDidMount: Called after the component has been mounted (i.e., added to the DOM).
    • componentDidUpdate: Called after the component has been updated (i.e., after a state change or prop change).
    • componentWillUnmount: Called before the component is unmounted (i.e., removed from the DOM).
  • We define a custom method incrementCount that updates the count state when a button is clicked.

  • In the render method, we display the current count and a button to increment it.

This class component demonstrates the use of state, lifecycle methods, and a custom method to manage and display state within a React component.

2. Props and State:

Props and State in React:

Props and state are fundamental concepts in React for managing data and communication between components. They serve different purposes:

  1. Props (Properties):

    • Props are read-only: They are used to pass data from parent components (or the parent component's state) to child components. Props are immutable, meaning they cannot be modified by the child component that receives them.

    • Props are external: They allow data to flow from top-down (from parent to child). They help in making components reusable and composable since child components can receive data from their parent components.

    • Props are used for configuration: You pass props to a component to configure its behavior or to provide data that it needs to display.

  2. State:

    • State is mutable: State is used to manage and store data that can change over time within a component. Unlike props, components can modify their own state using the setState method.

    • State is internal: It is local to the component where it is defined. Other components cannot directly access or modify another component's state.

    • State is used for interactivity: You use state to manage the internal state of a component. For example, you might use state to track form input, toggle a menu, or manage a counter.

Building a Component that Receives Props and Updates State: Certainly! Here's an example of a functional component in React that receives props and updates its state based on user interactions:

import React, { useState } from 'react';

function FunctionalComponent({ someProp }) {
  // Initialize state
  const [count, setCount] = useState(0);

  // Custom function to increment the count in state
  const incrementCount = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <h1>FunctionalComponent</h1>
      <p>Received Prop: {someProp}</p>
      <p>Current Count: {count}</p>
      <button onClick={incrementCount}>Increment Count</button>
    </div>
  );
}

export default FunctionalComponent;

3. Component Communication:

Implement parent-child communication using props.

In React, parent-child communication using props is a fundamental way to pass data from a parent component to a child component. Here's an example of how you can achieve parent-child communication using props in functional components:

ParentComponent.js:

import React, { useState } from 'react';
import ChildComponent from './ChildComponent';

function ParentComponent() {
  const [message, setMessage] = useState('Hello from Parent!');

  const handleMessageChange = () => {
    setMessage('Updated message from Parent!');
  };

  return (
    <div>
      <h1>Parent Component</h1>
      <p>Message: {message}</p>
      <button onClick={handleMessageChange}>Change Message</button>
      <ChildComponent message={message} />
    </div>
  );
}

export default ParentComponent;

ChildComponent.js:

import React from 'react';

function ChildComponent({ message }) {
  return (
    <div>
      <h2>Child Component</h2>
      <p>Received Message: {message}</p>
    </div>
  );
}

export default ChildComponent;

4. Convert a class component to a functional component using hooks.

Convert a class component to a functional component using hooks.

Sure, let's convert a class component to a functional component using hooks. Here's an example:

Class Component (Before Conversion):

import React, { Component } from 'react';

class CounterClassComponent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0,
    };
  }

  incrementCount = () => {
    this.setState((prevState) => ({
      count: prevState.count + 1,
    }));
  };

  render() {
    return (
      <div>
        <h1>Counter (Class Component)</h1>
        <p>Count: {this.state.count}</p>
        <button onClick={this.incrementCount}>Increment</button>
      </div>
    );
  }
}

export default CounterClassComponent;

Functional Component with Hooks (After Conversion):

import React, { useState } from 'react';

function CounterFunctionalComponent() {
  // Initialize state using the useState hook
  const [count, setCount] = useState(0);

  // Define a function to increment the count
  const incrementCount = () => {
    setCount((prevCount) => prevCount + 1);
  };

  return (
    <div>
      <h1>Counter (Functional Component with Hooks)</h1>
      <p>Count: {count}</p>
      <button onClick={incrementCount}>Increment</button>
    </div>
  );
}

export default CounterFunctionalComponent;

5. Conditional Rendering:

You can conditionally render a functional component in React based on a boolean value or user authentication by using a simple JavaScript conditional statement within your JSX. Here's an example:

import React from 'react';

function AuthenticatedComponent() {
  return <p>Welcome, authenticated user!</p>;
}

function UnauthenticatedComponent() {
  return <p>Please log in to access this content.</p>;
}

function App() {
  const isAuthenticated = true; // Replace with your authentication logic

  return (
    <div>
      <h1>Conditional Rendering Example</h1>
      {isAuthenticated ? <AuthenticatedComponent /> : <UnauthenticatedComponent />}
    </div>
  );
}

export default App;

6. Mapping and Lists:

Render a list of items using map and unique keys.

Add delete functionality to remove items from a list.

You can render a list of items using the map function and unique keys in a functional component in React. To add delete functionality to remove items from the list, you can create a delete button for each item and implement an event handler to handle the item removal. Here's an example:

import React, { useState } from 'react';

function ItemList() {
  const [items, setItems] = useState([
    { id: 1, text: 'Item 1' },
    { id: 2, text: 'Item 2' },
    { id: 3, text: 'Item 3' },
  ]);

  const handleDelete = (itemId) => {
    // Filter out the item with the given itemId
    const updatedItems = items.filter((item) => item.id !== itemId);
    setItems(updatedItems);
  };

  return (
    <div>
      <h1>Item List</h1>
      <ul>
        {items.map((item) => (
          <li key={item.id}>
            {item.text}
            <button onClick={() => handleDelete(item.id)}>Delete</button>
          </li>
        ))}
      </ul>
    </div>
  );
}

export default ItemList;

7. Forms and Controlled Components:

Create a controlled form component that updates state as the user types.

You can create a controlled functional form component in React that updates its state as the user types by using the useState hook to manage the form input's value and the onChange event handler to update the state. Here's an example:

import React, { useState } from 'react';

function ControlledForm() {
  // Initialize state for the form input
  const [formData, setFormData] = useState({
    firstName: '',
    lastName: '',
  });

  // Event handler to update form data
  const handleInputChange = (event) => {
    const { name, value } = event.target;
    setFormData({
      ...formData,
      [name]: value,
    });
  };

  return (
    <div>
      <h1>Controlled Form</h1>
      <form>
        <div>
          <label htmlFor="firstName">First Name:</label>
          <input
            type="text"
            id="firstName"
            name="firstName"
            value={formData.firstName}
            onChange={handleInputChange}
          />
        </div>
        <div>
          <label htmlFor="lastName">Last Name:</label>
          <input
            type="text"
            id="lastName"
            name="lastName"
            value={formData.lastName}
            onChange={handleInputChange}
          />
        </div>
      </form>
      <div>
        <p>First Name: {formData.firstName}</p>
        <p>Last Name: {formData.lastName}</p>
      </div>
    </div>
  );
}

export default ControlledForm;

Validate form input and show error messages.

To validate form input in a functional component and display error messages, you can add validation logic to your handleInputChange function and conditionally render error messages based on the validation results. Here's an example of how to do that:

import React, { useState } from 'react';

function ControlledFormWithValidation() {
  // Initialize state for the form input and error messages
  const [formData, setFormData] = useState({
    firstName: '',
    lastName: '',
  });

  const [errors, setErrors] = useState({
    firstName: '',
    lastName: '',
  });

  // Event handler to update form data and validate
  const handleInputChange = (event) => {
    const { name, value } = event.target;
    setFormData({
      ...formData,
      [name]: value,
    });

    // Validation logic (you can customize this as needed)
    if (name === 'firstName') {
      if (value.length < 2) {
        setErrors({
          ...errors,
          firstName: 'First name must be at least 2 characters long.',
        });
      } else {
        setErrors({
          ...errors,
          firstName: '',
        });
      }
    } else if (name === 'lastName') {
      if (value.length < 2) {
        setErrors({
          ...errors,
          lastName: 'Last name must be at least 2 characters long.',
        });
      } else {
        setErrors({
          ...errors,
          lastName: '',
        });
      }
    }
  };

  return (
    <div>
      <h1>Controlled Form with Validation</h1>
      <form>
        <div>
          <label htmlFor="firstName">First Name:</label>
          <input
            type="text"
            id="firstName"
            name="firstName"
            value={formData.firstName}
            onChange={handleInputChange}
          />
          {errors.firstName && <p className="error">{errors.firstName}</p>}
        </div>
        <div>
          <label htmlFor="lastName">Last Name:</label>
          <input
            type="text"
            id="lastName"
            name="lastName"
            value={formData.lastName}
            onChange={handleInputChange}
          />
          {errors.lastName && <p className="error">{errors.lastName}</p>}
        </div>
      </form>
    </div>
  );
}

export default ControlledFormWithValidation;

8. Event Handling:

Handle events like clicks, input changes, and form submissions.

In React, you can handle various events like clicks, input changes, and form submissions by defining event handlers. Here are examples for each of these event types:

  1. Click Events:

    To handle click events, you can use the onClick attribute on an HTML element like a button or a link. Here's an example of handling a click event:

    import React from 'react';
    
    function ClickEventExample() {
      const handleClick = () => {
        alert('Button clicked!');
      };
    
      return (
        <div>
          <h1>Click Event Example</h1>
          <button onClick={handleClick}>Click me</button>
        </div>
      );
    }
    
    export default ClickEventExample;

    In this example, when the "Click me" button is clicked, the handleClick function is executed, and an alert is shown.

  2. Input Change Events:

    To handle input changes, you can use the onChange attribute on an input element. Here's an example:

    import React, { useState } from 'react';
    
    function InputChangeExample() {
      const [inputValue, setInputValue] = useState('');
    
      const handleInputChange = (event) => {
        setInputValue(event.target.value);
      };
    
      return (
        <div>
          <h1>Input Change Event Example</h1>
          <input
            type="text"
            value={inputValue}
            onChange={handleInputChange}
            placeholder="Type something..."
          />
          <p>You typed: {inputValue}</p>
        </div>
      );
    }
    
    export default InputChangeExample;

    In this example, as the user types into the input field, the handleInputChange function updates the inputValue state, and the typed text is displayed.

  3. Form Submission Events:

    To handle form submissions, you can use the onSubmit attribute on a <form> element. Here's an example:

    import React, { useState } from 'react';
    
    function FormSubmitExample() {
      const [formData, setFormData] = useState({
        username: '',
        email: '',
      });
    
      const handleSubmit = (event) => {
        event.preventDefault();
        // Perform form submission logic (e.g., send data to the server)
        console.log('Form submitted with data:', formData);
      };
    
      const handleInputChange = (event) => {
        const { name, value } = event.target;
        setFormData({
          ...formData,
          [name]: value,
        });
      };
    
      return (
        <div>
          <h1>Form Submission Event Example</h1>
          <form onSubmit={handleSubmit}>
            <label htmlFor="username">Username:</label>
            <input
              type="text"
              id="username"
              name="username"
              value={formData.username}
              onChange={handleInputChange}
            />
            <label htmlFor="email">Email:</label>
            <input
              type="email"
              id="email"
              name="email"
              value={formData.email}
              onChange={handleInputChange}
            />
            <button type="submit">Submit</button>
          </form>
        </div>
      );
    }
    
    export default FormSubmitExample;

    In this example, when the form is submitted, the handleSubmit function is called, and we prevent the default form submission behavior using event.preventDefault(). The form data is then logged to the console, but you can replace that with your submission logic.

These examples demonstrate how to handle click events, input change events, and form submission events in React components. You can customize the event handlers to perform specific actions based on your application's requirements.

Demonstrate event delegation and event bubbling.

Event delegation and event bubbling are concepts that are not specific to React but are part of the DOM event handling mechanism. React utilizes these concepts as well because it's built on top of the DOM. Let's look at how event delegation and event bubbling work in a React context.

Event Bubbling:

Event bubbling is a mechanism in which an event triggered on a nested DOM element will propagate up the DOM tree, triggering the same event on its ancestors. In React, you can handle bubbling events by defining event handlers on parent components and allowing the events to propagate up to them. Here's an example:

import React from 'react';

function ParentComponent() {
  const handleParentClick = () => {
    alert('Parent Component Clicked');
  };

  return (
    <div onClick={handleParentClick} style={{ border: '1px solid #ccc', padding: '20px' }}>
      <h1>Parent Component</h1>
      <ChildComponent />
    </div>
  );
}

function ChildComponent() {
  const handleChildClick = () => {
    alert('Child Component Clicked');
  };

  return (
    <div onClick={handleChildClick} style={{ border: '1px solid #aaa', padding: '10px' }}>
      <h2>Child Component</h2>
      <button>Click Me (Child)</button>
    </div>
  );
}

export default ParentComponent;

Event Delegation:

Event delegation is a technique where you attach a single event listener to a common ancestor element of multiple child elements instead of attaching individual event listeners to each child element. In React, this can be achieved by handling events in a parent component and using the event.target property to determine which child element was the actual target of the event. Here's an example:

import React from 'react';

function ParentComponent() {
  const handleButtonClick = (event) => {
    if (event.target.tagName === 'BUTTON') {
      alert('Button clicked: ' + event.target.textContent);
    }
  };

  return (
    <div onClick={handleButtonClick}>
      <h1>Parent Component</h1>
      <button>Click Me 1</button>
      <button>Click Me 2</button>
    </div>
  );
}

export default ParentComponent;

9. Higher-Order Components (HOCs):

Create a higher-order component for reusable logic. Explain the benefits and use cases of HOCs.

Higher-Order Component (HOC) is a design pattern in React that allows you to reuse component logic. It's not a component itself but rather a function that takes a component and returns a new component with enhanced functionality. HOCs are a way to share behavior between components without duplicating code.

Here's a simple example of a Higher-Order Functional Component for reusable logic:

Sure, here's a simple example of implementing user authentication logic using a functional Higher-Order Component (HOC) in React:

import React, { useState } from 'react';

// Simulated authentication logic
const fakeAuthService = {
  isAuthenticated: false,
  login: () => {
    fakeAuthService.isAuthenticated = true;
  },
  logout: () => {
    fakeAuthService.isAuthenticated = false;
  },
};

// Define a Higher-Order Component (HOC) function
const withAuth = (WrappedComponent) => {
  // This HOC adds authentication-related props to the wrapped component
  return function WithAuth(props) {
    const [authenticated, setAuthenticated] = useState(fakeAuthService.isAuthenticated);

    const login = () => {
      fakeAuthService.login();
      setAuthenticated(true);
    };

    const logout = () => {
      fakeAuthService.logout();
      setAuthenticated(false);
    };

    // Pass authentication-related props to the wrapped component
    return (
      <WrappedComponent
        isAuthenticated={authenticated}
        login={login}
        logout={logout}
        {...props}
      />
    );
  };
};

// Create a component that requires authentication
const AuthenticatedComponent = ({ isAuthenticated, login, logout }) => {
  return (
    <div>
      <p>Welcome to the authenticated component!</p>
      <p>Authenticated: {isAuthenticated ? 'Yes' : 'No'}</p>
      {isAuthenticated ? (
        <button onClick={logout}>Logout</button>
      ) : (
        <button onClick={login}>Login</button>
      )}
    </div>
  );
};

// Wrap AuthenticatedComponent with the withAuth HOC
const AuthComponentWithAuth = withAuth(AuthenticatedComponent);

// App component
const App = () => {
  return (
    <div>
      <h1>Authentication Example</h1>
      <AuthComponentWithAuth />
    </div>
  );
};

export default App;

In this example:

  • We have a simulated authentication service (fakeAuthService) with login and logout functions.

  • The withAuth HOC takes a WrappedComponent and adds authentication-related props (isAuthenticated, login, and logout) to it.

  • The AuthenticatedComponent displays the user's authentication status and provides buttons for login and logout. The behavior of the buttons depends on the authentication status.

  • We wrap the AuthenticatedComponent with the withAuth HOC to create AuthComponentWithAuth.

  • In the App component, we render AuthComponentWithAuth to demonstrate how components wrapped with the withAuth HOC can access authentication-related props.

When you run this code, you'll see a simple authentication example where the user can log in and out, and the authentication status is passed as a prop to the wrapped component.

simple HOC example

 // Define an HOC function
  const withColor = (WrappedComponent, color) => {
    // This HOC adds a color prop to the wrapped component
    return (props) => <WrappedComponent {...props} color={color} />;
  };

  // Create a functional component to be wrapped
  const TextComponent = ({ text, color }) => (
    <div style={{ color }}>{text}</div>
  );

  // Wrap TextComponent with the withColor HOC
  const TextWithColor = withColor(TextComponent, "blue");

 <TextWithColor text="Colored text"></TextWithColor> 

10. Error Handling:

Implement error boundaries to catch and handle errors in React components. Discuss best practices for error handling.

Error boundaries in React can also be implemented in functional components using the useEffect and useState hooks. In this example, we'll create a functional error boundary and discuss best practices for error handling.

Implementing Error Boundaries in Functional Components:

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

// Functional error boundary component
const ErrorBoundary = ({ children }) => {
  const [hasError, setHasError] = useState(false);

  useEffect(() => {
    const errorHandler = (error) => {
      console.error(error);
      setHasError(true);
    };

    // Add a global error handler for uncaught errors
    window.addEventListener('error', errorHandler);

    // Clean up the event listener
    return () => {
      window.removeEventListener('error', errorHandler);
    };
  }, []);

  if (hasError) {
    // You can render a fallback UI when an error occurs
    return <div>Something went wrong.</div>;
  }

  return children;
};

// Example component that may throw an error
const MyComponent = () => {
  const throwError = () => {
    throw new Error('An error occurred');
  };

  return (
    <div>
      <button onClick={throwError}>Throw Error</button>
    </div>
  );
};

// App component
const App = () => {
  return (
    <div>
      <h1>Error Boundary Example</h1>
      <ErrorBoundary>
        <MyComponent />
      </ErrorBoundary>
    </div>
  );
};

export default App;

11. Lazy Loading and Suspense:

Implement code-splitting and lazy loading of components. Demonstrate how Suspense works with React.lazy and ErrorBoundary.

Code splitting and lazy loading of components in React allow you to load parts of your application only when they are needed, improving initial load times and reducing the size of the bundle. Additionally, React's Suspense component can be used with React.lazy and ErrorBoundary to handle loading and errors gracefully.

Here's how to implement code splitting, lazy loading, and demonstrate Suspense with React.lazy and ErrorBoundary in React functional components:

  1. Create a Dynamic Import

    First, create a dynamic import for the component you want to code split and lazy load. Let's assume we have a component called LazyComponent:

    // LazyComponent.js
    import React from 'react';
    
    const LazyComponent = () => {
      return <div>Lazy Component</div>;
    };
    
    export default LazyComponent;
  2. Lazy Load the Component

    Use React.lazy to dynamically load the component when needed. Wrap it with an ErrorBoundary to catch and handle any errors:

    // App.js
    import React, { Suspense } from 'react';
    
    // Define an ErrorBoundary component
    const ErrorBoundary = ({ children }) => {
      // Error handling logic here
    
      return children;
    };
    
    // Lazy load the component with React.lazy
    const LazyComponent = React.lazy(() => import('./LazyComponent'));
    
    const App = () => {
      return (
        <div>
          <h1>Lazy Loading and Suspense Example</h1>
          <ErrorBoundary>
            <Suspense fallback={<div>Loading...</div>}>
              <LazyComponent />
            </Suspense>
          </ErrorBoundary>
        </div>
      );
    };
    
    export default App;

    In the above code, we use React.lazy(() => import('./LazyComponent')) to load LazyComponent lazily when it's needed. The Suspense component wraps LazyComponent and provides a fallback UI (in this case, "Loading...") while the component is being loaded.

To implement a lazy-loaded component in routing in a React application, you can use React's React.lazy along with React Router. Lazy loading components in routing can significantly improve the initial load time of your application by loading components only when they are needed.

  1. Error Handling with ErrorBoundary

    Define an ErrorBoundary component to catch and handle errors. You can implement your error handling logic within this component:

    const ErrorBoundary = ({ children }) => {
      const [hasError, setHasError] = React.useState(false);
    
      React.useEffect(() => {
        // Simulate an error for demonstration purposes
        if (Math.random() > 0.5) {
          setHasError(true);
        }
      }, []);
    
      if (hasError) {
        return <div>Something went wrong.</div>;
      }
    
      return children;
    };

implement a lazy-loaded component in routing:

// App.js or your routing file
import React, { lazy, Suspense } from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';

// Create a dynamic import for the LazyComponent
const LazyComponent = lazy(() => import('./LazyComponent'));

const LoadingFallback = () => <div>Loading...</div>;

const App = () => {
  return (
    <Router>
      <Switch>
        <Route exact path="/" component={Home} />
        <Route
          path="/lazy"
          render={() => (
            <Suspense fallback={LoadingFallback}>
              <LazyComponent />
            </Suspense>
          )}
        />
        {/* Other routes */}
      </Switch>
    </Router>
  );
};

export default App;

12. Contextual Component Styling:

Style components using CSS-in-JS libraries like styled-components or Emotion. Discuss the benefits of styled-components.

styled-components

Styled-components and Emotion are popular CSS-in-JS libraries that allow you to style React components using JavaScript. These libraries provide a way to write and manage CSS directly within your JavaScript code. Below, I'll demonstrate how to style components using styled-components in a React functional component and discuss the benefits of using styled-components.

Using styled-components in a React Functional Component:

First, make sure you have styled-components installed in your project:

npm install styled-components

Here's an example of how to use styled-components in a React functional component:

import React from 'react';
import styled from 'styled-components';

// Create a styled component
const StyledButton = styled.button`
  background-color: #007bff;
  color: white;
  padding: 10px 20px;
  border: none;
  cursor: pointer;
  transition: background-color 0.3s;

  &:hover {
    background-color: #0056b3;
  }
`;

const App = () => {
  return (
    <div>
      <h1>Styled Components Example</h1>
      <StyledButton>Click me</StyledButton>
    </div>
  );
};

export default App;

Get post axios, fetch

You can use async/await syntax to make your code cleaner and easier to read when dealing with asynchronous operations like HTTP requests using fetch and Axios. Here's how you can rewrite the previous code snippets using async/await:

Using async/await with Fetch API:

// GET Request with Fetch and async/await
async function fetchPost() {
  try {
    const response = await fetch('https://jsonplaceholder.typicode.com/posts/1');
    if (!response.ok) {
      throw new Error('Network response was not ok');
    }
    const data = await response.json();
    console.log('GET Request with Fetch and async/await:', data);
  } catch (error) {
    console.error('Error:', error);
  }
}

// POST Request with Fetch and async/await
async function postNewData() {
  const postData = {
    title: 'foo',
    body: 'bar',
    userId: 1
  };

  try {
    const response = await fetch('https://jsonplaceholder.typicode.com/posts', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(postData)
    });
    if (!response.ok) {
      throw new Error('Network response was not ok');
    }
    const data = await response.json();
    console.log('POST Request with Fetch and async/await:', data);
  } catch (error) {
    console.error('Error:', error);
  }
}

// Call the functions
fetchPost();
postNewData();

Using async/await with Axios:

const axios = require('axios'); // Node.js environment

// GET Request with Axios and async/await
async function axiosGet() {
  try {
    const response = await axios.get('https://jsonplaceholder.typicode.com/posts/1');
    console.log('GET Request with Axios and async/await:', response.data);
  } catch (error) {
    console.error('Error:', error);
  }
}

// POST Request with Axios and async/await
async function axiosPost() {
  const postData = {
    title: 'foo',
    body: 'bar',
    userId: 1
  };

  try {
    const response = await axios.post('https://jsonplaceholder.typicode.com/posts', postData);
    console.log('POST Request with Axios and async/await:', response.data);
  } catch (error) {
    console.error('Error:', error);
  }
}

// Call the functions
axiosGet();
axiosPost();

In these examples, we use async functions (fetchPost, postNewData, axiosGet, axiosPost) to encapsulate the asynchronous operations, and we await the results of those operations. This makes the code more readable and easier to understand. Error handling is also done in a more structured way using try/catch blocks.

⚠️ **GitHub.com Fallback** ⚠️