codinggames

How to get the Redux State in a React 18 production build via the browser's console

Updated solution for accessing Redux state in a production build with React 18

Written in August 21, 2022 - 🕒 3 min. read

A few months ago, I published a blog post discussing the process of retrieving the Redux state from a production build through the browser’s console. However, this method no longer works after the release of React 18.

In this article, we will explore the reasons for this change and discuss how to create a new script that works with the latest version of React.

What changed?

In React 17, the _reactRootContainer property was present in the React container. However, this is no longer the case in React 18. Instead, the __reactContainer prefix with a random key at the end is used, as shown in the React source code.

To find the React container in React 18, we can search for DOM elements that contain a property starting with __reactContainer. To do this, we first need to find all potential DOM elements that could be the React container.

In most React apps, the container is set using an HTML id and queried with getElementById(). To find all elements with an id in the document, we can use document.querySelectorAll("*[id]").

To search for all React containers on the page, we can run the following script:

const internalRoots = Array.from(document.querySelectorAll("*[id]")).map((el) => {
    const key = Object.keys(el).filter((keyName) => keyName.includes('__reactContainer')).at(-1);

    return el[key];
}).filter((key) => key);

Done! Now all we have to do is find the _internalRoot and we’re set, right? Right?!?!

No

To be honest, it wasn’t too difficult to figure out the first part of this problem. However, as I am not very familiar with the React source code, I initially struggled to find a solution. Eventually, I decided to take a lazy approach and simply search through the container element’s properties for the Redux state.

As we all know, to retrieve the Redux state we use the getState() function. To access this function, we can perform a tree search within the React container variable.

Fortunately, there is already a GitHub Gist available that demonstrates how to do this. We can simply adapt this script to our specific use case, searching within a specific variable rather than at window.

const stores = new Set();
// code from https://gist.github.com/mindplay-dk/1843c267fc633688059dfa5e3b07d0dd
internalRoots.forEach((root) => {
    let seen = new Map();
    function search(obj) {
        if (seen.has(obj)) {
            return;
        }

        seen.set(obj, true);
        for (name in obj) {
            if (name === 'getState') {
                stores.add(obj);
            }

            if ((obj?.hasOwnProperty?.(name)) && (typeof obj[name] === "object") && (obj[name] != null)) {
                search(obj[name]);
            }
        }
    }

    search(root);
});

Done, now we can access the states with [...stores].map((store) => store.getState()).

redux state on instagram

You can copy and paste the full script below.

const internalRoots = Array.from(document.querySelectorAll("*[id]")).map((el) => {
    const key = Object.keys(el).filter((keyName) => keyName.includes('__reactContainer')).at(-1);

    return el[key];
}).filter((key) => key);

const stores = new Set();
// code from https://gist.github.com/mindplay-dk/1843c267fc633688059dfa5e3b07d0dd
internalRoots.forEach((root) => {
    let seen = new Map();
    function search(obj) {
        if (seen.has(obj)) {
            return;
        }

        seen.set(obj, true);
        for (name in obj) {
            if (name === 'getState') {
                stores.add(obj);
            }

            if ((obj?.hasOwnProperty?.(name)) && (typeof obj[name] === "object") && (obj[name] != null)) {
                search(obj[name]);
            }
        }
    }

    search(root);
});

[...stores].map((store) => store.getState());

Conclusion

To conclude, in this article we explored the reason why the previous method for accessing the Redux state in a production build stopped working in React 18 and presented an updated solution that allows for accessing the Redux state in production.

Although it was a challenge to discover the new method, with the help of an existing script and some modification, we were able to find a viable solution.

I hope that this article was helpful and that you will be able to use it in your own projects.

Tags:


Post a comment

Comments

ramsack on 8/9/23

Thank you for sharing this! Really helped me out

john on 9/10/22

Amazing!