Displaying Nested JSON in React/JSX - javascript

I have some JSON that is formatted like this:
{
card_id: "afe1500653ec682b3ce7e0b9f39bed89",
name: "A.J. Burnett",
playerattribute: {
team: "Marlins",
rarity: "Diamond",
}
}
I'm attempting to display the name and the team in a component. Here is what I have.
const PlayerProfile = ({ match, location }) => {
const { params: { cardId } } = match;
const [player, setPlayer] = useState(0);
useEffect(() => {
const fetchData = async () => {
const result = await axios(
`http://127.0.0.1:8000/api/player-profiles/${cardId}/?format=json`,
).then((result) => {
setPlayer(result.data);
});
};
fetchData();
}, []);
return (
<Container component="main">
Name: {player.name}
Team: {player.playerattribute.team}
</Container>
)
}
export default PlayerProfile;
However, I get this error: TypeError: Cannot read property 'team' of undefined
The name works fine. So I'm assuming it's an issue with the nested JSON.

You probably shouldn't instanciate your player state with 0 if the projected value is an object.
The error comes up because you try to access a property of an object property that doesn't exist at creation.
Basically, your code tries to do this: {0.playerattribute.team}
0.playerattribute => undefined
Workaround would be a conditionnal render or a default initial value of your state that matches the JSX needs.
const PlayerProfile = ({ match, location }) => {
const { params: { cardId } } = match;
const [player, setPlayer] = useState({
name: "",
playerattribute: {
team: ""
}
});
useEffect(() => {
const fetchData = async () => {
const result = await axios(
`http://127.0.0.1:8000/api/player-profiles/${cardId}/?format=json`,
).then((result) => {
setPlayer(result.data);
});
};
fetchData();
}, []);
return (
<Container component="main">
Name: {player.name}
Team: {player.playerattribute.team}
</Container>
)
}
export default PlayerProfile;
or
const PlayerProfile = ({ match, location }) => {
const { params: { cardId } } = match;
const [player, setPlayer] = useState(null);
useEffect(() => {
const fetchData = async () => {
const result = await axios(
`http://127.0.0.1:8000/api/player-profiles/${cardId}/?format=json`,
).then((result) => {
setPlayer(result.data);
});
};
fetchData();
}, []);
return (
<Container component="main">
Name: {player?.name}
Team: {player?.playerattribute?.team}
</Container>
)
}
export default PlayerProfile;

Set useState const [player, setPlayer] = useState("");

const [player, setPlayer] = useState({
Name: '',
Team: ''
}}
//on your setPlayer you may
const playerData = result.data;
setPlayer({
Name: playerData.name
Team: playerData.playerattribute.team})
if you still getting same error, please provide screenshot of console.log(result)

Related

Displaying response from API in react component

I'm trying to display the response from the API into my react component but it's not working. If I try to use it in the console, I can see the data and its value but not in the react component, it's empty when I try to show the value in a div.
Here is the code where I'm trying to display it in my react component:
const CharacterListing = () => {
const characters = useSelector(getAllCharacters);
console.log("Hello", characters);
const renderCharacters = Object.entries(characters).map(([key, value]) => {
console.log(value.name);
<div>{value.name}</div>
})
return (
<div>
{renderCharacters}
</div>
);
};
export default CharacterListing;
This is the code for my Character Slice Component
const initialState = {
characters: {},
};
const characterSlice = createSlice({
name: 'characters',
initialState,
reducers: {
addCharacters: (state, { payload }) => {
state.characters = payload;
},
},
});
export const { addCharacters } = characterSlice.actions;
export const getAllCharacters = (state) => state.characters.characters;
export default characterSlice.reducer;
This is the code for my Home Component:
const Home = () => {
const dispatch = useDispatch();
useEffect(() => {
const fetchCharacters = async () => {
const response = await baseURL.get(`/characters`)
.catch(error => {
console.log("Error", error);
});
dispatch(addCharacters(response.data));
console.log("Success", response);
};
fetchCharacters();
}, [])
return (
<div>
Home
<CharacterListing />
</div>
);
};
export default Home;
Thank you
You forgot to return item into your map func
Try this :
const renderCharacters = Object.entries(characters).map(([key, value]) => {
console.log(value.name);
return <div key={key}>{value.name}</div>
})

Having problems iterating the data from a nested json Api

I am fetching data
I have a brand property and I am trying to display it, and I am trying to implement a click setCurrentSelectedBrand logic to diplay the data of that specific brand[object]. Currently I am getting the TypeError: Cannot read property 'brand' of undefined error in the Main Component, I dont know why
Data
[{
"a_class":[
{
"brand":"A-class",
"id":"1",
"year":"2015"
"price":"12665"
...
"engine_spec":{
...
}
...
}],
"b_class":[
{
"brand":"B-class",
"id":"2",
"year":"2016"
"price":"12665"
...
"engine_spec":{
...
}
...
}],
}
]
Main Component
const Cars = () => {
const { cars, handleSelectBrand} = useContext(CarsContext)
return (
<div>
{Object.keys(cars).map((key:any, index)=>{
let brands:any = cars[key];
return (
<div key={key} onClick={() => handleSelectBrand(key)} className='brand__list' >
{brands[0].brand}
</div>
);})}
<CarsDetails />
</div>
)
}
export default Cars
Context
declare module 'axios' {
export interface AxiosResponse<T = any> extends Promise<T> {}
}
export const CarsProvider:React.FC <IProps> = ({ children } ) => {
const [isLoading, setIsLoading] = useState(false);
const [cars, setCars] =useState< any | ICars[] >([])
const [brands, setBrands] = useState([])
const [currentSelectedBrand, setCurrentSelectedBrand] = useState('')
const handleSelectBrand = React.useCallback((brand) => {
return setCurrentSelectedBrand(cars[brand]);
},[cars])
useEffect(()=>{
const fetchData = async () => {
setIsLoading(true);
const response = await api.get('/cars', {
});
setIsLoading(false)
setCars([...response.data]);
setCurrentSelectedBrand(response[Object.keys(response)[0]]);
console.log(response.data)
};
fetchData()
},[brands, cars])

Destructuring the data in React

So the thing I am trying to do is to destructure coinsData, so I can use the id globally and keep the coinsData so I can iterate it somewhere else. Right now I am having a problem with typescript on export CoinProvider Type '({ children }: { children?: ReactNode; }) => void' is not assignable to type 'FC<{}>'Help would be appreciated
import React,{FC, useState, useEffect} from 'react'
export interface Coin {
id:string;
name: string;
current_price: number;
symbol:string;
price_change_percentage_24h:number
image:string;
market_cap:number
market_cap_rank:number
}
export const CoinContext = React.createContext<Coin[] | undefined>(undefined)
export const CoinProvider:FC= ({children}) => {
const [loading, setLoading] =useState(false)
const [page, setPage] = useState(1);
const [totalPages, setTotalPages] = useState(10);
const [coinsData, setCoinsData] = useState<Coin[]>([])
const handlePrevPage = () => {
setPage((prevPage) => prevPage - 1);
};
const handleNextPage = () => {
setPage((nextPage) => nextPage + 1);
};
useEffect(()=>{
const fetchData= async()=>{
setLoading(true);
const response= await fetch(`https://api.coingecko.com/api/v3/coins/markets?
vs_currency=usd&order=market_cap_desc&page=${page}&per_page=10&sparkline=false`)
const result = await response.json()
setCoinsData(result);
setTotalPages(totalPages);
setLoading(false)
}
fetchData()
},[page, totalPages])
const Coins = coinsData.map((item) => {
const {
id,
} = item
return(
<CoinContext.Provider value={{Coins, totalPages, id, loading, handlePrevPage, handleNextPage,
currentPage:{ page }}}>
{children}
</CoinContext.Provider>
)
}
You forgot about }) in line 47.
And logic there should look like this:
const Coins = coinsData.map((item) => item.id)
Your component is missing a return statement.
Make sure to return an HTML that can be rendered.
return <>
{coinsData.map((item) => {
const { id } = item
return (
<CoinContext.Provider value={[{ id: 'id', current_price: 1, image: 'image', market_cap: 0, market_cap_rank: 0, name: 'name', price_change_percentage_24h: 0, symbol: 'symbol' }]}>
{children}
</CoinContext.Provider>
)
})
}
</>
And, don't forget to close the map function with the parenthesis )
In case, you only want to pass coinsData
return <CoinContext.Provider value={...coinsData}>
{children}
</CoinContext.Provider>
you can renounce the map and simplify your code with destructuring your coinsData directly.

How to update an object that is within an array

How can I put data into object values in an array in javaScript? I am taking data from the backend using axios and useEffect hook! taking data I need to push that data into an object which is inside of the array! code I wrote doesn't work and ignorant! there is a JS question!
const Articles = () => {
const [articleData, setArticleData] = useState([]);
useEffect(() => {
const fetchBlogs = async () => {
try {
const res = await axios.get(
`${process.env.REACT_APP_API_URL}/article/list/all`
);
setArticleData(res.data);
} catch (err) {}
};
fetchBlogs();
}, []);
for (let article in articleData) {
data: [
{
key: article._id,
title: article.title,
author_username: article.author_username,
category: article.category_name,
subcategory: article.subCategory_name,
publication_date: article.publication,
},
],
}
return (
<div className='articles'>
<Table
columns={columns}
dataSource={data}
size='large'
/>
</div>
)
};
You can use map to get a new array, then save it to the state and use the state variable in JSX. Something like this should work for you
const Articles = () => {
const [articleData, setArticleData] = useState([]);
useEffect(() => {
const fetchBlogs = async () => {
try {
const res = await axios.get(
`${process.env.REACT_APP_API_URL}/article/list/all`
);
setArticleData(res.data.map(article => ({
key: article._id,
title: article.title,
author_username: article.author_username,
category: article.category_name,
subcategory: article.subCategory_name,
publication_date: article.publication,
})));
} catch (err) {}
};
fetchBlogs();
}, []);
return (
<div className='articles'>
<Table
columns={columns}
dataSource={articleData}
size='large'
/>
</div>
)
};

Testing React component with data provided by custom hook

I have created this custom hook to fetch data:
const useSuggestionsApi = () => {
const [data, setData] = useState({ suggestions: [] });
const [url, setUrl] = useState('');
const [loading, setLoading] = useState(false);
const [error, setError] = useState(false);
useEffect(() => {
const fetchData = () => {
setError(false);
setLoading(true);
if(url) {
fetch(url).then((res) => {
if (res.status !== 200) {
console.error(`It seems there was an problem fetching the result. Status Code: ${res.status}`)
return;
}
res.json().then((fetchedData) => {
setData(fetchedData)
})
}).catch(() => {
setError(true)
})
setLoading(false);
};
}
fetchData();
}, [url]);
return [{ data, loading, error }, setUrl];
}
export default useSuggestionsApi;
It used used in this component to render the response (suggestions).
const SearchSuggestions = ({ query, setQuery}) => {
const [{ data }, doFetch] = useSuggestionsApi();
const { suggestions } = data;
useEffect(() => {
const encodedURI = encodeURI(`http://localhost:3000/search?q=${query}`);
doFetch(encodedURI);
}, [doFetch, query]);
return (
<div className="search-suggestions__container">
<ul className="search-suggestions__list">
{suggestions.map((suggestion) => {
return (
<li className="search-suggestions__list-item" key={uuid()}>
<span>
{suggestion.searchterm}
</span>
</li>
)
})}
</ul>
</div>
);
};
export default SearchSuggestions;
Now I would like to write some unit test for the SearchSuggestions component but I am lost on how to mock the returned data from useSuggestionApi. I tried importing useSuggestionApi as a module and then mocking the response like this but with no success:
describe('SearchSuggestions', () => {
const wrapper = shallow(<SearchSuggestions/>)
it('test if correct amount of list-item elements are rendered', () => {
jest.mock("../hooks/useSuggestionsApi", () => ({
useSuggestionsApi: () => mockResponse
}));
expect(wrapper.find('.search-suggestions__list').children()).toHaveLength(mockResponse.data.suggestions.length);
});
})
I am new to testing React components so very grateful for any input!
This works:
jest.mock('../hooks/useSuggestionsApi', () => {
return jest.fn(() => [{data: mockResponse}, jest.fn()]
)
})
describe('SearchSuggestions', () => {
const wrapper = shallow(<SearchSuggestions query="jas"/>)
it('correct amount of list-items gets rendered according to fetched data', () => {
expect(wrapper.find('.search-suggestions__list').children()).toHaveLength(mockResponse.suggestions.length);
});
})

Categories