2
respostas

Múltiplas rerenderizações

Eu fiz o curso e apliquei também em outras situações. Mas tive um problema: múltiplas renderizações. No aplicativo (um blog simples) que estou desenvolvendo aplicando o que foi ensinado no curso eu criei um AppContext para guardar contextos da aplicação, como postagens em destaques, categorias, etc.

Esse é o código do AppContext

import React, { createContext, useReducer } from 'react';
import { reducer } from './../reducers/appDataReducer';

export const AppContext = createContext();

const initialState = {
    categorias: [],
    destaques: [],
    videosEmDestaque: []
}

export const AppProvider = ({children}) => {
    const [appData, dispatch] = useReducer(reducer, initialState);

    return (
        <AppContext.Provider value={{appData, dispatch}}>
            {children}
        </AppContext.Provider>
    );
}

Fiz um reducer, para lidar com os estados

export const FETCH_CATEGORIAS = 'FETCH_CATEGORIAS';
export const FETCH_DESTAQUES = 'FETCH_DESTAQUES';
export const FETCH_VIDEOS_DEVOCIONAIS_EM_DESTAQUE = 'FETCH_VIDEOS_EM_DESTAQUE';

export const reducer = (state, action) => {
    console.log('action', action)
    switch(action.type) {
        case FETCH_CATEGORIAS:
            return {...state, categorias: action.payload}
        case FETCH_DESTAQUES:
            return {...state, destaques: action.payload}
        case FETCH_VIDEOS_EM_DESTAQUE:
            return {...state, videosEmDestaque: action.payload}
        default:
            return state;
    }
}

Aí eu fiz um hook para lidar com os fetchs e dispatches

import { useContext } from "react";
import { AppContext } from "../context/AppContext";
import { FETCH_CATEGORIAS, FETCH_DESTAQUES, FETCH_VIDEOS_EM_DESTAQUE } from './../reducers/appDataReducer';
import axios from './../plugins/axios/axios';

const fetchCategoriasAction = (payload) => ({
    type: FETCH_CATEGORIAS,
    payload: payload
});

const fetchDestaquesAction = (payload) => ({
    type: FETCH_DESTAQUES,
    payload: payload
});

const fetchVideosEmDestaqueAction = (payload) => ({
    type: FETCH_VIDEOS_EM_DESTAQUE,
    payload: payload
});

export const useAppContext = () => {
    const { appData, dispatch } = useContext(AppContext);
    const { categorias, destaques, videosEmDestaque } = appData;

    const fetchCategorias = () => {
        if (!categorias.length) {
            axios.get('/categorias')
                .then(response => dispatch(fetchCategoriasAction(response.data)))
                .catch(error => console.log(error));
        }
    };

    const fetchDestaques = () => {
        if(!destaques.length){
            axios.get('/postagens/destaques')
                .then(response => dispatch(fetchDestaquesAction(response.data)))
                .catch(error => console.log(error));
        }
    };

    const fetchVideosEmDestaque = () => {
        if(!videosEmDestaque.length){
            axios.get('/videos/destaques?categoriaId=1')
                .then(response => dispatch(fetchVideosEmDestaqueAction(response.data)))
                .catch(error => console.log(error));
        }
    }

    return  {
        destaques,
        categorias,
        videosEmDestaque,
        fetchCategorias,
        fetchDestaques,
        fetchVideosEmDestaque,
    }
}

Com isso pronto, pensei poder usar o Hook para lidar com os estados da aplicação, algo similar ao Redux. Mas é aqui que estou enfrentando dificuldade. Sempre que o chamo em algum componente da aplicação, ele faz múltiplas renderizações. Por exemplo: em Layout.jsx eu faço essa chamada:

///...
const Layout = ({children, hasSidebar = true}) => {
    const { destaques, categorias, fetchCategorias } = useAppContext();

    useEffect(() => {
        fetchCategorias();
    }, []);
    //...

Ela gera 4 chamadas do request para o back-end. Não estou sabendo como resolver, já que não é um dado computado.

2 respostas

Eu ainda não sei se há algo de errado no código que informei acima, entretanto eu fiz a mesma implementação com Redux e o problema persistiu. Bem, eu estava usando lazy load das páginas nas rotas. Pensei que esse fosse um ponto de quebra, portanto eu deixei o carregamento das páginas de modo estático e isso fez com que as renderizações caíssem pela metade. Depois removi o Strict Mode do React e ficou com a quantidade de renderizações corretas.

Gostaria de saber se há uma forma de continuar usando o lazy load sem causar rerenderizações.

Oii, Naun! Tudo bem?

Fico feliz que esteja praticando o que aprendeu no curso em outros contextos, parabéns!

Naum, Como não estou totalmente inteirada no contexto do seu projeto, posso te ajudar com apenas algumas possibilidades do que pode estar acontecendo.

Ao usar o useContext acaba re-renderizando o componente sempre que o contexto muda, que neste caso, é atualizado a cada vez que é feito uma requisição no back-end, levando a várias chamadas sem necessidade.

Uma coisa importante a verificar é se as mudanças de estado dentro do seu useReducer estão causando re-renderizações desnecessárias nos componentes que consomem o contexto. Isso pode acontecer se o objeto de estado retornado pelo reducer estiver sendo considerado como um novo objeto a cada dispatch, mesmo que os valores não tenham efetivamente mudado.

Uma sugestão é utilizar o método useMemopara a memorização do valor passado para o componente, garantindo que o componente seja re-renderizado somente quando o contexto mudar.

O Lazy pode ser útil para otimizar o carregamento da aplicação, mas ele pode causar re-renderizações adicionais.

Naum, essas sugestões precisam ser adaptadas de acordo com as características de todo o código, então readapte e realize os testes.

Espero ter ajudado de alguma forma. Qualquqer dúvida, conte conosco.

Bons estudos!

Quer mergulhar em tecnologia e aprendizagem?

Receba a newsletter que o nosso CEO escreve pessoalmente, com insights do mercado de trabalho, ciência e desenvolvimento de software