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