My Redux project uses Redux-Thunk to work with an API, it doesn’t render the Header.js element as it was supposed to, I’ll show you the files (they are VERY short). I won’t waste time showing the store and App.js because I’m sure it is correctly configured. (but if you want I’ll share)
Redux > actions:
export const FETCH_CHARACTERS_BEGIN = 'FETCH_CHARACTERS_BEGIN';
export const FETCH_CHARACTERS_SUCCESS = 'FETCH_CHARACTERS_SUCCESS';
export const FETCH_CHARACTERS_FAILURE = 'FETCH_CHARACTERS_FAILURE';
export const actionFetchCharactersBegin = () => ({
type: FETCH_CHARACTERS_BEGIN,
});
export const actionFetchCharactersSucess = (characters) => ({
type: FETCH_CHARACTERS_SUCCESS,
payload: characters,
});
export const actionFetchCharactersFailure = (error) => ({
type: FETCH_CHARACTERS_FAILURE,
payload: error,
});
const API = 'https://rickandmortyapi.com/api/character';
export function fetchCharacters() {
return async (dispatch) => {
dispatch(actionFetchCharactersBegin());
try {
const response = await fetch(API);
const { results } = await response.json();
dispatch(actionFetchCharactersSucess(results));
return results;
} catch (error) {
dispatch(actionFetchCharactersFailure(error));
}
};
};
redux > reducers:
import {
FETCH_CHARACTERS_BEGIN,
FETCH_CHARACTERS_SUCCESS,
FETCH_CHARACTERS_FAILURE
} from '../actions';
const initialState = {
characters: [],
loading: false,
error: null
}
export default function characterReducer(state = initialState, action) {
switch (action.type) {
case FETCH_CHARACTERS_BEGIN:
return {
...state,
loading: true,
error: null
};
case FETCH_CHARACTERS_SUCCESS:
return {
...state,
loading: false,
characters: [...state.characters, action.payload]
};
case FETCH_CHARACTERS_FAILURE:
return {
...state,
loading: false,
error: action.payload,
characters: []
}
default:
return state;
}
};
components > Header.js:
import React, { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { fetchCharacters } from '../redux/actions';
import './Header.css'
function Header() {
const characters = useSelector(state => state.characters);
const loading = useSelector(state => state.loading);
const error = useSelector(state => state.error);
const dispatch = useDispatch();
useEffect(() => {
dispatch(fetchCharacters())
}, [dispatch]);
if (loading) {
return <div>Loading...</div>
};
if (error) {
return <div>{error.message}</div>
};
return (
<div className='container-header'>
<div className='header'>
<div className='header_logo'>
<div className='logo_text'>
<h3>Rick And Morty Character's</h3>
</div>
</div>
<h1>Characters</h1>
<ul>
{characters.map(character => (
<li key={character.id}>
{character.name} ({character.status})
</li>
))}
</ul>
</div>
</div>
)
}
export default Header;
can someone help me to find out the problem?
2
Answers
strange, it still doesn't render anything on the screen, can you check what's wrong in the repository for me? I'll send the link:
https://github.com/eliasef/rick-and-morty-api
Issue
The only issue/discrepancy I see in the code is in the
characterReducer
reducer function in theFETCH_CHARACTERS_SUCCESS
success case. ThefetchCharacters
action returns an array of characters, but theFETCH_CHARACTERS_SUCCESS
case incorrectly nests this result array in thestate.characters
array.In other words, each time
FETCH_CHARACTERS_SUCCESS
runs it nests an array in an array.The result is that
state.characters
looks something like[[{ id: 1, name: "Rick Sanchez", …}, ...]]
.Solution
You can either save the payload array directly:
Or if you are actually using the paginated results you can spread the payload: