Cannot read property 'map' of undefined [React.js] - javascript

so when i do my login and i try to redirect to this page it appears me that error it must be something with useEffect i dont know
here is my code
useEffect(() => {
let canUpdate = true;
getVets().then((result) => canUpdate && setVets(result));
return function cleanup() {
canUpdate = false;
};
}, []);
const getVets = async () => {
const url = 'http://localhost:8080/all/vet';
const response = await fetch(url);
const data = await response.json();
setVets(data);
};
// const { appointmentType, animalID, room, hora, notes } = this.state;
return (
<React.Fragment>
<div class='title'>
<h5>2 médicos vetenários disponíveis</h5>
</div>
<div>
{vets.map((data) => (
<ObterMedicos
key={data.name}
name={data.name}
specialty={data.specialty}
/>
))}
</div>
</React.Fragment>
);
}

vets might not have data on the first render and when the code tries to execute map operation on it, it gets undefined.map, which is not allowed.
You can either set vets to empty array at the time of defining the state
const [vets,setVets] = useState([]);
or just check on vets using Optional chaning (?) before using the map function:
{vets?.map((data) => (
<ObterMedicos
key={data.name}
name={data.name}
specialty={data.specialty}
/>
))}

Related

How can I display the results of map function in jsx?

I'm slowly learning react and trying to display the results of my searchMap function (movie title/poster) with the TMDB API. I can log the information I need to the console, but I get undefined variables and other errors when trying to display the information in the commented div.
https://codesandbox.io/s/ddmdu4
function App() {
const search = async (event) => {
const searchQuery = event.target.value;
if (searchQuery) {
const searchReq = await fetch(
`https://api.themoviedb.org/3/search/movie?api_key=${process.env.API_KEY}&query=${searchQuery}`
).then((res) => res.json());
const searchResults = searchReq.results;
searchMap(searchResults);
}
};
const searchMap = (searchResults) => {
searchResults.map((movie) => {
console.log(`${movie.title}`);
console.log(`${movie.backdrop_path}`);
});
};
return (
<div className="App">
<div>
<input type="text" onChange={search} placeholder="Search"></input>
</div>
<div>{/* Display movie title/poster*/}</div>
</div>
);
}
export default App;
Since you want to update the DOM each time the result changes I would recommend using that inside of a state like so:
const [searchResults, setSearchResults] = React.useState([]);
In your async search function update the state by using its appropiate "setter":
.then((res) => res.json());
setSearchResults(searchReq.results);
And inside your return you can map the result as follows:
<div>
{searchResults.map((movie) => (
<>
<div>{movie.title}</div>
<div>{movie.backdrop_path}</div>
</>
))}
</div>

React map is not rendering names from array, only flickers because aync/await bug

React is not rendering my mapped array after using asyn functions to call on API
I use the following useEffect to get characters into an array and set it as state in setRelatedCharacters
// Find related characters
useEffect(() => {
// for promise to work in useEffect. need to put async function inside then call it
const relatedCharacters = async () => {
// if data exist. set related characters array by calling utility function and wait for it
if (data) setRelatedCharacters(await relatedSwapi(data.characters));
};
relatedCharacters();
}, [data]);
Then, when logging relatedCharacters, I get an array of 17 objects(characters).
Next, I send a condition to wait until the array is full of characters and when full I try to map through the array and render a name for each object in array. However, it quickly flickers and then disappears. I have no idea why.
{!data && !relatedCharacters ? (
<Loading />
) : (
<div>
<p>hello</p> // renders
{console.log(relatedCharacters, "<= relatedCharacters")} // shows correct array
{relatedCharacters?.map((character) => (
<p key={character.name}>{character.name}</p> //DOESN'T SHOW, SLIGHTLY FLICKERS ONLY
))}
</div>
)
-- EDIT FOR COMMENT --
Here is the entire code once taking away everything else
const Film = () => {
const location = useLocation();
const url = location.state.url;
const index = location.state.index;
const [data, setData] = useState(null);
const [relatedCharacters, setRelatedCharacters] = useState(null);
// Find related characters
// PROBLEM HAS TO BE HERE I THINK AS PROMISES AND SUCH ARE ACTING UP
const relatedSwapi = (data) => {
let relatedArray = [];
data.map(async (url) => {
const related = await callSingleSwapi(url);
relatedArray.push(related);
});
return relatedArray;
};
useEffect(() => {
const fetchCharacters = async () => {
// if data exist. set related characters array by calling utility function and wait for it
if (data) {
const x = await relatedSwapi(data.characters);
setRelatedCharacters(x);
}
};
fetchCharacters();
}, [data]);
return (
<div>
<div className="relatedWrapper">
<div className="flex space-x-3">
{console.log(relatedCharacters, "<= related Characters")} // RENDERS AND THEN GOES BACK TO NULL
{relatedCharacters?.map((character) => (
<p key={character.name}>{character.name}</p>
))}
</div>
</div>
)}
</div>
);
};
export default Film;
Here is console.log(relatedCharacters)

ReactJS how to update page after fetching data

I'm new to ReactJS and I'm now trying to do an interactive comments section (taken from frontendmentor.io), but the App component just doesn't show what it's supposed to show
This is my App component:
function App() {
const [data, setData] = useState([]);
useEffect(() => {
const getComm = async () => {
await fetchData();
};
getComm();
}, []);
console.log(data);
const fetchData = async () => {
const res = await fetch("db.json").then(async function (response) {
const comm = await response.json();
setData(comm);
return comm;
});
};
return (
<Fragment>
{data.length > 0 ? <Comments data={data} /> : "No Comments to Show"}
</Fragment>
);
}
export default App;
The console.log(data) logs two times:
the first time it's an empty Array;
the second time it's the Array with my datas inside.
As it follows:
If I force the App to print the Comments it just says that cannot map through an undefined variable
This is my Comments component:
function Comments({ data }) {
return (
<div>
{data.map((c) => (
<Comment key={c.id} />
))}
</div>
);
}
export default Comments;
I'm wondering why the page still displays No Comments to Show even if the log is correct
#Cristian-Irimiea Have right about response get from fetch. Response is an a object and can't be iterate. You need to store in state the comments from response
But you have multiple errors:
Take a look how use async function. Your function fetchData looks bad.
// Your function
const fetchData = async () => {
const res = await fetch("db.json").then(async function (response) {
const comm = await response.json();
setData(comm);
return comm;
});
};
// How can refactor
// fetchData function have responsibility to only fetch data and return a json
const fetchData = async () => {
const response = await fetch("./db.json");
const body = await response.json();
return body;
};
You are updating state inside fetch function but a good solution is update state then promise resolve:
useEffect(() => {
// here we use .then to get promise response and update state
fetchData().then((response) => setData(response.comments));
}, []);
The initial state of your data is an array.
After you fetch your data from the response you get an object. Changing state types is not a good practice. You should keep your data state as an array or as an object.
Considering you will keep it as an array, you need use an array inside of setData.
Ex.
comm && Array.isArray(comm.comments) && setData(comm.comments);
As for your Comments component you should consider expecting an array not an object.
Ex.
function Comments(data) {
return (
<div>
{data.map((c) => (
<Comment key={c.id} />
))}
</div>
);
}
export default Comments;

React Query with server side rendering using Next.js

I am trying to use react-query with nextjs to prefetch query on server. It works for the initial query which gets a list of items. However when I try to fetch each item inside component it only fetches it on the client side.
export default function Home() {
const { data } = useQuery("pokemons", fetchPokemons);
return (
<>
<div>
{data.map((pokemon) => (
<Pokemon key={pokemon.name} pokemon={pokemon}/>
))}
</div>
</>
);
}
export async function getStaticProps() {
const queryClient = new QueryClient()
await queryClient.prefetchQuery('pokemons', fetchPokemons)
const fetchedPokemons = queryClient.getQueryData()
//query each pokemon
fetchedPokemons.forEach(async (pokemon) => {
await queryClient.prefetchQuery(pokemon.name, () => fetchPokemon(pokemon.url))
});
return {
props: {
dehydratedState: dehydrate(queryClient),
},
}
}
And here is code for the component which also queries each item.
const Pokemon = ({pokemon}) => {
const {data} = useQuery(pokemon.name, () => fetchPokemon(pokemon.url))
// logs only in browser, on server it is undefined
{console.log(data)}
return (
<div>
<h3>
Name - {data.name}
</h3>
<h4>Base XP - {data.base_experience}</h4>
</div>
)
}
Can you please tell me what am I doing wrong that the query doesn't execute on server or is it an issue of the library itself?
when you use getQueryData to get data from the cache, you need to provide the key of the data you want to get:
await queryClient.prefetchQuery('pokemons', fetchPokemons)
const fetchedPokemons = queryClient.getQueryData('pokemons')
alternatively, you can use fetchQuery to also retrieve the data immediately
try {
const fetchedPokemons = await queryClient.fetchQuery('pokemons')
} catch (error) {
// handle error
}
Be aware that fetchQuery throws errors (as opposed to prefetchQuery, which does not), so you might want to handle errors somehow.
I was able to solve this by combining two of my fetching functions into one like so
const fetchPokemons = async () => {
const { data } = await axios.get(
"https://pokeapi.co/api/v2/pokemon?limit=10&offset=0"
);
const pokemonArray = await Promise.all(
data.results.map(async (pokemon) => {
const res = await axios.get(pokemon.url);
return res.data;
})
);
return pokemonArray;
};
export default function Home() {
const { data } = useQuery("pokemons", fetchPokemons);
return (
<>
<div>
{data.map((pokemon) => (
<Pokemon key={pokemon.name} pokemon={pokemon}/>
))}
</div>
</>
);
}
export async function getStaticProps() {
const queryClient = new QueryClient();
await queryClient.prefetchQuery("pokemons", fetchPokemons);
return {
props: {
dehydratedState: dehydrate(queryClient),
},
};
}

shopping cart array not rendering properly, react.js

after a fetch if I click to some card I am able to populate an empty array.
I would like to pass it as a prop to a child component and I guess I am doing the right way, the problem occurs when within the children I am trying to console log it because I can not see any errors and the console.log is not printing anything
let shoppingCart = [];
const fetchProducts = async () => {
const data = await fetch(
"blablablablablab"
);
const products = await data.json();
setProducts(products);
console.log(products);
};
const handleShoppingCart = product => {
shoppingCart.push(product);
console.log(shoppingCart);
return shoppingCart;
};
Inside the return function I tried to check if the array was not empty, if was not undefined or if was not null but with the same result
{shoppingCart.length !== 0 ? (
<ShoppingCart parkingSlots={shoppingCart} />
) : null}
children component
const ShoppingCart = ({ parkingSlots }) => {
console.log(parkingSlots);
const parkingSlotsComponent = parkingSlots.map((parkingSlot, i) => {
// const { name } = parkingSlot;
return (
<div className="parking_details" key={i}>
{parkingSlot.name}
</div>
);
});
return <div className="checkout">{parkingSlotsComponent}</div>;
};
The data is in props.
When data is passed to child component via props, then it is part of props child component. Try below and see if you can console log the data.
const ShoppingCart = props => {
console.log(props.parkingSlots);
const parkingSlotsComponent = props.parkingSlots.map((parkingSlot, i) => {
// const { name } = parkingSlot;
return (
<div className="parking_details" key={i}>
{props.parkingSlot.name}
</div>
);
});
return <div className="checkout">{parkingSlotsComponent}</div>;
};

Categories

Resources