An open API service indexing awesome lists of open source software.

https://github.com/ch0ripain/react-class-based-components

🧙‍♂️ React class-based components 🧙‍♂️
https://github.com/ch0ripain/react-class-based-components

react react-class-components reactjs

Last synced: 10 months ago
JSON representation

🧙‍♂️ React class-based components 🧙‍♂️

Awesome Lists containing this project

README

          

🧙‍♂️ React class-based components 🧙‍♂️

Class-based components were used a lot a while ago, more specifically in versions prior to React 16.8. In that version React added hooks and with that a more functional way of working based on functional components.

In this project I will demonstrate how to translate functional components to class components and also where one can continue using class based components and how to use some class oriented hooks like useState(), useEffect(), useContext().

## ⚡️Functional component to class-based component
```javascript
//Functional
const User = (props) => {
return

  • {props.name}
  • ;
    };

    //Class
    import { Component } from 'react';
    class User extends Component {
    constructor(){
    super()
    }

    render (){
    return

  • {this.props.name}
  • ;
    }
    }

    //Using a class component is the same thing

    ```

    - Component must be imported from React
    - User must extends Component ➡️ it allow to use all the methods from the parent (Component)
    - constructor() ➡️ enables you to provide any custom initialization that must be done before any other methods can be called on an instantiated object.
    - super() ➡️ call the constructor of its parent class to access the parent's properties and methods
    - render() ➡️ inherited method that allows to render the value inside
    - this ➡️ to refer our class props context (props are automatically forwarded by react)

    In the example given above the constructor() and super() are not really needed because i don't want to provide any custom initialization or change any inherited property like state from the parent.

    ---
    ### ⚡️useState()
    ```javascript
    //Functional
    import { useState } from 'react';

    const Users = () => {

    const [showUsers, setShowUsers] = useState(true);

    const toggleUsersHandler = () => {
    setShowUsers((curState) => !curState);
    };

    return (



    {showUsers ? 'Hide' : 'Show'} Users

    {showUsers && usersList}

    )

    //Class
    class Users extends Component {
    constructor() {
    super();
    this.state = { showUsers: true }
    }

    toggleUsersHandler() {
    this.setState((prevState) => {
    return { showUsers: !prevState.showUsers }
    })
    }

    render() {
    ...
    return (



    {this.state.showUsers ? 'Hide' : 'Show'} Users

    {this.state.showUsers && usersList}

    )
    }
    ```

    The changes I need to make to manage state in my class shown above are:
    - this.state ➡️ property inherited from the Component whose value must always be an Object ➡️ {}
    - toggleUsersHandler() ➡️ as my class method and also using the keyword this to refer my class context
    - this.state.showUsers ➡️ always refer to the state on my class
    - bind() ➡️ to pass data as an argument to the function of a class based component for context purposes

    > [!NOTE]
    > You can avoid use "bind" syntax if you use arrow function syntax instead ➡️ toggleUsersHandler() = () => { ... };

    If you want to know more about bind take a look on these links

    [ReactJS-Bind-Method-GG](https://www.geeksforgeeks.org/reactjs-bind-method/)

    [ReactJS-Bind-Method-StackOverflow](https://stackoverflow.com/questions/60774235/what-does-bindthis-is-exactly-doing-in-this-example-of-the-react-app#:~:text=%22bind%22%20method%20is%20used%20to,the%20value%20of%20parent%20component.)

    ---
    ### ⚡️useEffect()
    ```javascript
    //Class
    class UserFinder extends Component {
    constructor() {
    super()
    this.state = { filteredUsers: DUMMY_USERS, searchTerm: '' }
    }

    searchChangeHandler(event) {
    this.setState({ searchTerm: event.target.value })
    }

    //Loading users when component is rendered
    componentDidMount() {
    this.setState({ filteredUsers: DUMMY_USERS })
    }

    //Updating users with state/props changes
    componentDidUpdate(prevProps, prevState) {
    if (prevState.searchTerm !== this.state.searchTerm) {
    this.setState({ filteredUsers: DUMMY_USERS.filter((user) => user.name.includes(this.state.searchTerm)) })
    }
    }

    render() {...}
    }
    ```
    When using useEffect() on class-based component there are 3 main methods that allow me to handle that hook:

    - componentDidMount() ➡️ equivalent to useEffect() without deps, only executed once the component is rendered.
    - componentDidUpdate() ➡️ equivalent to useEffect() with deps, it is executed every time a property or state changes. We also need to manage those changes and what will happen next.
    - componentWillUnmount() ➡️ equivalent to useEffect() cleanup function, executed when the component is unmounted

    This is a example of componentWillUnmount()
    ```javascript
    class User extends Component {
    ...
    componentWillUnmount() {
    console.log('User component unmounted')
    }
    ...
    }
    ```
    ---
    ### ⚡️Using Context in Class-based components
    ```javascript
    //First i create my context on my standalone context file
    import React from 'react';

    const UsersContext = React.createContext({
    users: []
    });

    export default UsersContext;
    ```
    ```javascript
    //Then i wrap a parent component in common with all the update state logic
    import UsersContext from './store/users-context';

    function App() {
    const usersContext = {
    users: DUMMY_USERS
    }

    return (



    );
    }
    ```
    ```javascript
    //Last, use the context in the child component i want
    import UsersContext from '../store/users-context';
    class UserFinder extends Component {
    ...
    //defining context
    static contextType = UsersContext; //always must be static contextType prop
    ...
    //state
    constructor() {
    super()
    this.state = { filteredUsers: [], searchTerm: '' }
    }
    ...
    //using the context
    componentDidMount() {
    this.setState({ filteredUsers: this.context.users })
    }
    ```
    ---
    ### ⚡️Error Boundaries
    This is probably the main reason to use a class-based component nowadays, as React doesn't support error handling yet (it could barely be implemented using try catch or something like that)
    ```javascript
    //Create your error boundary as a class component and handle all error logic within it.
    class ErrorBoundary extends Component {
    constructor() {
    super();
    this.state = { hasError: false }
    }

    componentDidCatch(error) {
    console.log(error)
    this.setState({ hasError: true })
    }

    render() {
    if (this.state.hasError) {
    return

    Something went wrong D:


    }
    return this.props.children //If no error catched just return the children component value
    }
    }
    ```
    - componentDidCatch() ➡️ catches exceptions generated in child components.

    ```javascript
    // Wrap child components where errors should occur
    import ErrorBoundary from './ErrorBoundary';

    //Dummy error on Users.js
    componentDidUpdate() {
    if (this.props.users.length === 0) {
    throw new Error('No users provided')
    }
    }
    ```
    So if an error occurs in a child component that is wrapped with my error-component boundary class with all the error logic, this would be rendered:
    ```javascript
    render() {
    if (this.state.hasError) {
    return

    Something went wrong D:

    //This message will be seen by the user
    }
    return this.props.children
    }
    ```
    ---

    🐸 This project is a practice exercise I learned from the Academind's React Course 🐸