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
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>
})
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])
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 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>
)
};
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);
});
})