Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

183
Visualizações
Need help showing content from redux store

I am trying to retrieve information from my backend and display it. I can fetch the data to my redux store fine but when I try to display it on the page I get a cannot read property 'title' of undefined error. Doesn't always occur but whenever I refresh it does. Any ideas? Here is the file in question. Happy to share other information but I am pretty confident both my backend and redux are working properly because I can retrieve and display data elsewhere.

import '../../styles/article.css';
import { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { getThread } from '../../store/actions/forum_actions';
import { clearThread } from '../../store/actions';
const Thread = (props) => {
  const [loading, setLoading] = useState(true);
  const threads = useSelector((state) => state.threads);
  const thread = threads?.current;
  const dispatch = useDispatch();

  useEffect(() => {
    dispatch(getThread(props.match.params.id));
    setLoading(false);
  }, [dispatch, props.match.params.id]);

  useEffect(() => {
    return () => {
      dispatch(clearThread());
    };
  }, [dispatch]);

  return (
    <>
      {loading ? (
        <>
          <p>Loading</p>
        </>
      ) : (
        <>
          <p>{thread.title}</p>
        </>
      )}
    </>
  );
};

export default Thread;

Here is the reducer:

import { ADD_THREAD, GET_THREADS, GET_THREAD, CLEAR_THREAD } from '../types';

export default function threadReducer(state = {}, action) {
  switch (action.type) {
    case ADD_THREAD:
      return { ...state, lastThreadAdded: action.payload, success: true };
    case GET_THREADS:
      return { ...state, threads: action.payload };
    case GET_THREAD:
      return { ...state, current: action.payload };
    case CLEAR_THREAD:
      return { ...state, current: null };

    default:
      return state;
  }
}

Here is the action

import * as threads from './index';
import axios from 'axios';
import { getAuthHeaders } from '../../components/utils/tools';

axios.defaults.headers.post['Content-Type'] = 'application/json';

export const getThread = (id) => {
  return async (dispatch) => {
    const request = await axios.get(`/forum/thread/${id}`);
    dispatch(threads.getThread(request.data));

    try {
    } catch (error) {
      dispatch(threads.errorGlobal('Error retrieving thread'));
    }
  };
};
about 4 years ago · Juan Pablo Isaza
3 Respostas
Responde à pergunta

0

The reason it's happening is because the action you are dispatching is Async (dispatch(getThread(props.match.params.id));) and hence code execution will not wait for the API result it will execute the next statement which is setLoading(false). You are making your loading stop before API response and hence you are getting undefined error.

Solution:

Reduder:

import { ADD_THREAD, GET_THREADS, GET_THREAD, CLEAR_THREAD, LOADING_THREAD } from '../types';

export default function threadReducer(state = {}, action) {
  switch (action.type) {
    case LOADING_THREAD:
      return { ...state, loadingThreads: action.payload }; //modified
    case ADD_THREAD:
      return { ...state, lastThreadAdded: action.payload, success: true };
    case GET_THREADS:
      return { ...state, threads: action.payload };
    case GET_THREAD:
      return { ...state, current: action.payload };
    case CLEAR_THREAD:
      return { ...state, current: null };

    default:
      return state;
  }
}

Action:

import * as threads from './index';
import axios from 'axios';
import { getAuthHeaders } from '../../components/utils/tools';

axios.defaults.headers.post['Content-Type'] = 'application/json';

export const getThread = (id) => {
  return async (dispatch) => {
try {
    dispatch(threads.loadingThread(true));
    const request = await axios.get(`/forum/thread/${id}`);
    dispatch(threads.getThread(request.data));
    dispatch(threads.loadingThread(false));

    
    } catch (error) {
    dispatch(threads.loadingThread(false));
      dispatch(threads.errorGlobal('Error retrieving thread'));
    }
  };
};

Component:

import '../../styles/article.css';
import { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { getThread } from '../../store/actions/forum_actions';
import { clearThread } from '../../store/actions';
const Thread = (props) => {
  const threads = useSelector((state) => state.threads);
  const loading = useSelector((state) => state.loadingThreads); //modified
  const thread = threads?.current;
  const dispatch = useDispatch();

  useEffect(() => {
    dispatch(getThread(props.match.params.id));
    setLoading(false);
  }, [dispatch, props.match.params.id]);

  useEffect(() => {
    return () => {
      dispatch(clearThread());
    };
  }, [dispatch]);

  return (
    <>
      {loading ? (
        <>
          <p>Loading</p>
        </>
      ) : (
        <>
          <p>{thread.title}</p>
        </>
      )}
    </>
  );
};

export default Thread;
about 4 years ago · Juan Pablo Isaza Relatório

0

I would suggest to have defined initialState for the reducer

instead

state = {}

const initialState = {
current:{},
threads: [],
success: false 
}

function threadReducer(state = initialState, action)

this will help you managing the in-between state.

Also loading state in the component is not always aligned. Consider using

isLoading = useSelector(loadingSelector)

instead useState

about 4 years ago · Juan Pablo Isaza Relatório

0

You can simplify Redux async flows implementing the repository pattern without a middleware to handle an API call and dispatch a state. Api calls can be also encapsulated into hooks. For example, take a look to this piece of code, it's not related to your project, but you can use it as a starting point:

export const useCustomerRepository = () => {
  const dispatch = useDispatch<Dispatch<CustomerAction>>();

  const customerState = useSelector((state: RootState) => state.customerState);
  const customerApi = useCustomerApi();

  const list = async () => {
    try {
      dispatch({ type: 'CUSTOMER:LISTING', flag: true });
      const customers = await handleAxiosApi<Customer[]>(customerApi.list());
      dispatch({ type: 'CUSTOMER:LIST', customers });
    } catch (error) {
      dispatch({ type: 'CUSTOMER:LIST_FAILED', message: getResponseErrorMessage(error) });
    } finally {
      dispatch({ type: 'CUSTOMER:LISTING', flag: false });
    }
  };

  return {...customerState};
};

You can take a look to the full working example here to simplify your code.

about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda