Share value between components – React JS

In this article, I will show you, how you can share value between multiple components in React JS. If you are new to React JS, check this tutorial to setup React JS in your project.

Step 1:

First, we are going to create a global state variable. This will be like a simple Javascript object.

<script>
    const globalState = {
        state: {
            user: null
        },
    }
</script>

In the state object, you can define all the variables, with their default values, that you want to share between components in React JS.

Step 2:

Then you need to create an array that will hold callback functions of all components for whom the value will be shared.

const globalState = {
    state: {
        user: null
    },

    listeners: [],
}

After that, we will create a function that will be called from the React JS component.

const globalState = {
    state: {
        user: null
    },

    listeners: [],

    listen (callback) {
        this.listeners.push(callback)
    },
}

This will accept a callback function that will be defined in the component (later in this tutorial). And that callback function will be pushed into the listeners array.

And create final method in this object will update the values of the state in this object. That function will also call the callback function of all the components are listening to this state. And inside that callback will send the new state object as well as the state currently updated in this call.

const globalState = {
    state: {
        user: null
    },

    listeners: [],

    listen (callback) {
        this.listeners.push(callback)
    },

    setState (newState) {
        const self = this

        this.state = {
            ...this.state,
            ...newState
        }

        this.listeners.forEach(function (callback) {
            callback(self.state, newState)
        })
    }
}

Step 3:

Now we need to create a component in React JS and set the state of this object.

<div id="header"></div>

<script type="text/babel">
    function Header() {
        React.useEffect(function () {
            globalState.setState({
                user: {
                    name: "Muhammad Adnan Afzal"
                }
            })
        }, [])

        return (
            <h1>Header</h1>
        )
    }

    ReactDOM.createRoot(
        document.getElementById("header")
    ).render(<Header />)
</script>
  1. First, we are updating the globalState.state object. Passing the object will update only the provided values. So even if your globalState has more variables in state object, this will only update the variables that are passed in setState method.
  2. This will also call all the listeners callback function from globalState as well. But right now, the listeners array is empty. It will only have value when some component listens to it.

Step 4:

We will create another component that will listen to this global state by calling the subscribe method.

<div id="content"></div>

<script type="text/babel">
    function Content() {
        const [state, setState] = React.useState(globalState.state)

        React.useEffect(function () {
            globalState.listen(function (newState, updatedState) {
                setState(newState)

                // check which state is updated
                if (typeof updatedState.user !== "undefined") {
                    //
                }
            })
        }, [])

        return (
            <>
                { state.user != null && (
                    <p>{ state.user.name }</p>
                )}

                <h1>Content</h1>
            </>
        )
    }

    ReactDOM.createRoot(
        document.getElementById("content")
    ).render(<Content />)
</script>
  1. First, we are creating a state variable and initializing it with the globalState.state variable. So, initially, the value of state inside Header component will be same as in globalState object.
  2. Then we are calling the subscribe method and passing a callback function in it.
  3. This callback function will only be called when the globalState.setState is called from Header component.
  4. When this callback is called, we are updating the state variable with what is received from Header component.

Now you will be able to view the user name in Content component, the user name that you have set from Header component. That’s how you can share value between components in React JS.

Complete code:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>State</title>

        <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.development.js"></script>
        
        <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.development.min.js"></script>
        
        <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.23.10/babel.js"></script>
    </head>

    <body>
        <script>
            const globalState = {
                state: {
                    user: null
                },

                listeners: [],

                listen (callback) {
                    this.listeners.push(callback)
                },

                setState (newState) {
                    const self = this

                    this.state = {
                        ...this.state,
                        ...newState
                    }

                    this.listeners.forEach(function (callback) {
                        callback(self.state, newState)
                    })
                }
            }
        </script>

        <div id="header"></div>

        <script type="text/babel">
            function Header() {
                React.useEffect(function () {
                    setTimeout(function () {
                        globalState.setState({
                            user: {
                                name: "Muhammad Adnan Afzal"
                            }
                        })
                    }, 1000)
                }, [])

                return (
                    <h1>Header</h1>
                )
            }

            ReactDOM.createRoot(
                document.getElementById("header")
            ).render(<Header />)
        </script>

        <div id="content"></div>

        <script type="text/babel">
            function Content() {
                const [state, setState] = React.useState(globalState.state)

                React.useEffect(function () {
                    globalState.listen(function (newState, updatedState) {
                        setState(newState)

                        // check which state is updated
                        if (typeof updatedState.user !== "undefined") {
                            //
                        }
                    })
                }, [])

                return (
                    <>
                        { state.user != null && (
                            <p>{ state.user.name }</p>
                        )}

                        <h1>Content</h1>
                    </>
                )
            }

            ReactDOM.createRoot(
                document.getElementById("content")
            ).render(<Content />)
        </script>
    </body>
</html>

Download

WordPress – Disable multiple image sizes

If you are using WordPress, you will notice that when you upload an image media, it creates multiple images of different resolutions. In this article, I will show you how you can disable multiple image sizes on WordPress.

Open your active theme’s functions.php file. It will be in “wp-content/themes/{your_active_theme_name}/functions.php”. Then add the following 2 hooks at the top of functions.php file:

function wpb_remove_image_sizes($sizes) {
    unset($sizes['thumbnail']);
    unset($sizes['medium']);
    unset($sizes['medium_large']);
    unset($sizes['large']);
    return $sizes;
}
add_filter('intermediate_image_sizes_advanced', 'wpb_remove_image_sizes');

function wpb_stop_generate_media_sizes($sizes) {
    return array();
}
add_filter('intermediate_image_sizes', 'wpb_stop_generate_media_sizes');

Refresh the page and try uploading a new image. You will now see that it will be uploaded just once. Let me know if you face any problem in this.

Search in all fields in DataTable

If you are using the DataTable Javascript library and are having trouble searching in all fields of the dataset except for the only one visible, then I will show you, how you can search in all fields of the DataTable.

By default, DataTable searches in all fields only on those fields that are visible on the table. Let’s say you have a dataset containing “name”, “designation”, and “country” fields. But you are displaying only “name”, and “designation” on the table.

<?php
    $data = [
        [ "name" => "Adnan", "designation" => "Software Engineer", "country" => "Pakistan" ],
        [ "name" => "John", "designation" => "Web Designer", "country" => "USA" ],
        [ "name" => "Burak", "designation" => "Cloud Engineer", "country" => "Turkey" ],
        [ "name" => "Sachin", "designation" => "Mobile Engineer", "country" => "India" ],
    ];
?>

<table id="example" class="display" style="width: 100%;">
    <thead>
        <tr>
            <th>Name</th>
            <th>Designation</th>
        </tr>
    </thead>
    
    <tbody>
        <?php foreach ($data as $d): ?>
            <tr>
                <td>
                    <?php echo $d["name"]; ?>
                </td>

                <td>
                    <?php echo $d["designation"]; ?>
                </td>
            </tr>
        <?php endforeach; ?>
    </tbody>
</table>

<script>
    new DataTable('#example')
</script>

Right now, you will be able to search by name and designation only because only these two are visible on the table.

But what if you want to search for country as well ?

You just need to create a hidden <div> element and render the complete dataset in it using json_encode PHP function.

<?php
    $data = [
        [ "name" => "Adnan", "designation" => "Software Engineer", "country" => "Pakistan" ],
        [ "name" => "John", "designation" => "Web Designer", "country" => "USA" ],
        [ "name" => "Burak", "designation" => "Cloud Engineer", "country" => "Turkey" ],
        [ "name" => "Sachin", "designation" => "Mobile Engineer", "country" => "India" ],
    ];
?>

<table id="example" class="display" style="width: 100%;">
    <thead>
        <tr>
            <th>Name</th>
            <th>Designation</th>
        </tr>
    </thead>
    
    <tbody>
        <?php foreach ($data as $d): ?>
            <tr>
                <td>
                    <div style="display: none;">
                        <?php echo json_encode($d); ?>
                    </div>
                    
                    <?php echo $d["name"]; ?>
                </td>

                <td>
                    <?php echo $d["designation"]; ?>
                </td>
            </tr>
        <?php endforeach; ?>
    </tbody>
</table>

<script>
    new DataTable('#example')
</script>

If you are trying to search the country, you will be able to see the records of that country, despite the country is not visible in that table.

That’s how you can search in all fields of the DataTable, despite the fact if they are visible or not.

Source code:

Download

Send response from other method in Laravel

In Laravel, generally, you can send the response back to the client only from the method that was directly called from the route. But there is a way to send a response from other method as well.

Let’s say you created the following route:

// routes/web.php

use App\Http\Controllers\UserController;

Route::get("/response-other-method", [UserController::class, "responseOtherMethod"]);

And in your UserController class, you have the following 2 methods:

// App/Http/Controllers/UserController.php

namespace App\Http\Controllers;

class UserController extends Controller
{
    public function otherMethod()
    {
        return response()->json([
            "message" => "Hello Laravel"
        ]);
    }

    public function responseOtherMethod()
    {
        $this->otherMethod();
    }
}

Note that the function “responseOtherMethod()” is called directly from the route. But it is further calling the “otherMethod()” function. Right now, you will see an empty blank page when you access that route:

http://localhost/laravel/response-other-method

Laravel is calling both of these functions, it is just not returning the response from the second function. To return the response from otherMethod() method, just call throwResponse() from it.

Solution

return response()->json([
    "message" => "Hello Laravel"
])->throwResponse();

You will be able to see the response now If you access that route again. Learn more on Laravel.

CMD picking the wrong PHP version

Sometimes CMD picks the wrong version of PHP and not the one we install via XAMPP or MAMP.

Let’s say you have downloaded and installed XAMPP or MAMP with the latest PHP. But when you run the command “php -v” in your terminal, it displays the wrong version of PHP (typically the previously installed version of PHP). This is a common issue when you try to upgrade your PHP version. Previously, you could have upgraded the PHP version easily using Homebrew. But nowadays, Homebrew itself has become too complex and it has its errors.

Problem with Laravel 10

You will also face that error when you try to create a project in Laravel 10+ version. Because Laravel 10 requires PHP greater than 8 and a lot of developers are using PHP 7. The reason why developers are still using PHP 7 is because most of the shared hosting servers are still running on PHP 7. As PHP 8 is a big upgrade, a lot of things have been changed. So changing the PHP version could crash the entire project. On the local computer, it’s fine. But if you have a live website or an API, a crashed website means losing a lot of users and potentially a lot of customers which results in a loss of revenue (which no one wants).

Updating PHP version

To update the PHP version, you simply need to open CMD anywhere in your computer and run the following command:

export PATH="/Applications/MAMP/bin/php/php8.2.0/bin:$PATH"

Here, you can change the path to your own PHP file. Typically, it is in your XAMPP/MAMP “bin” folder. Inside “bin”, you will find the “php” folder. Inside that folder, you can go to your desired PHP version folder. And every PHP version folder also has a “bin” folder in it. Go it in and paste its path there.

The above line is for Mac users. For Windows users, the path will look like:

export PATH="C:\XAMPP\bin\php\php8.2.0\bin:$PATH"

Check PHP version

After that, you need to close the terminal and open it again. Then run the following command to verify the PHP version:

php -v

Now, you should be able to see your selected PHP version.

So that’s it. That’s how you can upgrade your PHP if your CMD is picking the wrong PHP version. If you face any issues with this, kindly do let me know.

Show placeholder image in ReactJS

Imagine if you are displaying an image from the server in your React app. And the image gets deleted from the server. You do not want to show the broken image icon, as it does not look professional. You can show a placeholder image in your ReactJS App if the original image fails to load.

The following code will by default show the “Jackie Chan 2.jpg” image. If that image fails to load, it will render the “default-img.jpg” image inside the “img” folder.

Be careful: If the placeholder image does not exist as well, it will stuck in an infinite loop. To solve this problem, DO NOT save the placeholder image on the server. Always keep the placeholder images on the client side.

function MyApp() {
	const { useState } = React
	const [image, setImage] = useState("img/Jackie Chan 2.jpg")

	return (
		<>
			<h1>Hello React JS</h1>

			<img src={ image }
				style={{
					width: "100%"
				}}
				onError={function () {
					event.target.src = "img/default-img.jpg"
				}} />
		</>
	)
}

ReactDOM.createRoot(
	document.getElementById("app")
).render(<MyApp />)

As an example, you can use this image as a placeholder. Make sure to download it in your “img” directory. That’s how you can show a placeholder image in ReactJS if the original image fails to load. You can also read more articles on ReactJS.