Como acessar o state do Redux de um build de produção do React 18

Escrito em 21 de agosto de 2022 - 🕒 2 min. de leitura

Alguns meses atrás, EU escrevi um post no blog sobre como obter o state do Redux em produção, mas com o recente lançamento do React 18, esse código não funciona mais.

Vamos mergulhar no motivo pelo qual ELE não funciona mais e descobrir como criar um script que funcione.

O que mudou?

No React 17, o container do React continha uma propriedade chamada _reactRootContainer, e esse não é mais o caso do React 18, como podemos ver no código-fonte do React, que agora usa __reactContainer como um prefixo com uma chave aleatória no final.

Com isso em mente, podemos tentar encontrar o container React verificando se ele contém uma propriedade começando com __reactContainer, mas antes disso, precisamos encontrar todos os elementos DOM potenciais que poderiam ser o container React.

A maioria dos aplicativos React usa um id do HTML para definir o container e, em seguida, usa a função getElementById() para pega-lo, então para pegar todos os elementos com um id no documento, podemos usar document.querySelectorAll("*[id ]").

Para encontrar todos os containers React na página, podemos executar o seguinte script:

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

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

Pronto! Agora tudo o que temos a fazer é encontrar o _internalRoot e pronto, né? Né?!?!

Não

Para falar a verdade, essa primeira parte foi bem fácil de descobrir, e como não estou muito familiarizado com o código-fonte do React, após tentar mergulhar em todas as propriedades disponíveis do container, decidi ser preguiçoso e usar a solução mais fácil.

Ok, então sabemos que podemos obter o state do Redux através da função getState(), então tudo o que precisamos fazer é uma busca na árvore da variável do container do React. Fácil.

Felizmente, já existe um GitHub Gist para isso, então tudo o que precisamos fazer é adaptá-lo ao nosso caso, então analisamos uma variável específica em vez da 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);
});

Pronto, e daí podemos acessar os states com [...stores].map((store) => store.getState()).

redux state on instagram

Você pode copiar e colar o script completo abaixo.

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

    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());

E é isso! Nos vemos na próxima!

Tags:


Publicar um comentário

Comentários

john em 10/09/2022

Amazing!