I'm new to React and Redux, and I'm trying to make an app based on a public Animal Crossing API. I was having issues initially because after I got the data from the API and tried to map in the component, it said it was an object. I read a lot of different things on StackOverflow. I tried using Object.entries on the initial API response, that helped somewhat. I was able to make a card component for each villager. But I can't access the props in the data itself to have the names, personalities, and birthdays show up. I've been trying to do my first API call for about 3 weeks and tried several different projects and tutorials but I end up hitting a wall since I'm a beginner and still pretty confused.
Can someone try looking at my code to see where I'm going wrong?
This is my actions & initial API call:
import { FETCH_CHARACTERS_REQUEST, FETCH_CHARACTERS_SUCCESS, FETCH_CHARACTERS_FAILURE } from "./actiontypes";
import axios from 'axios';
export const fetchCharactersRequest = () => {
return {
type: FETCH_CHARACTERS_REQUEST
}
}
const fetchCharactersSuccess = characters => {
return {
type: FETCH_CHARACTERS_SUCCESS,
payload: characters
}
}
const fetchCharactersFailure = error => {
return {
type: FETCH_CHARACTERS_FAILURE,
payload: error
}
}
export const fetchCharacters = () => {
return (dispatch) => {
dispatch(fetchCharactersRequest)
axios.get('https://acnhapi.com/v1/villagers')
.then(response => {
const characters = Object.entries(response.data)
dispatch(fetchCharactersSuccess(characters))
})
.catch(error => {
const errorMsg = error.message
dispatch(fetchCharactersFailure(errorMsg))
})
}
}
This is my reducer & initial state:
import {
FETCH_CHARACTERS_REQUEST,
FETCH_CHARACTERS_SUCCESS,
FETCH_CHARACTERS_FAILURE
} from './actiontypes';
const initialState = {
characters: [],
isLoading: false,
error: ''
}
const reducer = (state = initialState, action) => {
switch(action.type) {
case FETCH_CHARACTERS_REQUEST:
return {
...state,
isLoading: true
}
case FETCH_CHARACTERS_SUCCESS:
return {
...state,
characters: action.payload,
error: ''
}
case FETCH_CHARACTERS_FAILURE:
return {
loading: false,
characters: [],
error: action.payload
}
default: return state
}
}
export default reducer;
This is where I'm having a lot of issues with my mapping. I was able to successfully console.log(characterData.characters[0][1].personality) for the first villager, but I don't know how to get that right on the map.
import React, {useEffect} from 'react';
import {connect} from 'react-redux';
import {fetchCharacters} from '../features/characterActions';
import CharacterCard from './CharacterCard';
function CharacterProfile({fetchCharacters, characterData}) {
useEffect(() => {
fetchCharacters()
}, [])
const listVillagers = characterData.characters.map((villager) =>
<CharacterCard key={villager.key} data={villager} />
)
console.log(listVillagers)
return characterData.isLoading ? (
<h2>Loading...</h2>
) : characterData.error ? (
<h2>{characterData.error}</h2>
) : (
<div>
<h2>Animal Crossing Villagers</h2>
<div>
{listVillagers}
</div>
</div>
)}
const mapStateToProps = state => {
return {
characterData: state.character
}
}
const mapDispatchToProps = dispatch => {
return {
fetchCharacters: () => dispatch(fetchCharacters())
}
}
export default connect(mapStateToProps, mapDispatchToProps)(CharacterProfile)
And this is the character card where I was attempting to get the information from the data.
import React from 'react'
function CharacterCard({name, birthday}) {
return (
<div>
<h2>Name: {name}</h2>
</div>
)
}
export default CharacterCard
Also, this is where I'm pulling the data from if it helps: https://acnhapi.com/v1/villagers
I feel like these are the main places that I could have gone wrong. I really need help because it's starting to drive me insane.
CodePudding user response:
In CharacterProfile component, you can try to console your "villager"
const listVillagers = characterData.characters.map((villager) => console.log(villager) )
it would be an array with 2 elements, like this:
["ant00", {"id": 1,"file-name": "ant00","name": {...}, "personality": "Cranky", ...]
so if you only need second element in villager, you shold pass it like this:
const listVillagers = characterData.characters.map((villager) => <CharacterCard key={villager.key} data={villager[1]} /> )
because you pass villager[1] as "data" prop to CharacterCard, so in this component, you should destrucure props to "data" prop
function CharacterCard({ data }) { ... }
and your "data" is a object includese properties "name", "birthday", ..., so if you want to access them, you also need to destructure from "data"
const { name, birthday } = data;
your name is a object, too.
"name": { "name-USen": "Cyrano", "name-EUen": "Cyrano", ... }
so you cannot render it in div directly, if you want to render "name-USen", you should use name["name-USen"]
<h2>Name: {name["name-USen"]}</h2>
Here is the complete code:
import React from "react";
function CharacterCard({ data }) {
const { name, birthday } = data;
return (
<div>
<h2>Name: {name["name-USen"]}</h2>
<h2>Birthday: {birthday}</h2>
</div>
);
}
export default CharacterCard;