I am trying to display the image of the breed selected by the user in this code but it is not working,
any ideas or hints as of why?
Thank you
import React, { useState, useEffect } from 'react';
import './breed-image.css';
function BreedImage () {
const [breed, selectedBreed] = useState('');
useEffect(() => {
fetchImage();
}, []);
const fetchImage = async () => {
const res = await fetch(`https://dog.ceo/api/breed/${breed}/images/random`)
const data = await res.json();
const imageUrl = data.message
selectedBreed(imageUrl);
};
return (
<div className="image-container">
<img className="image-card" src={breed} alt="doggopicture" />
</div>
);
}
export default BreedImage;
There's some weird logic in here that doesn't make sense. breed is initialized to an empty string. Then, in your useEffect you have an empty dependencies array, which means it will be called once. Which means your API request hits https://dog.ceo/api/breed//images/random which presumably would fail (since breed was '').
Most likely you instead want:
import React, { useState, useEffect } from 'react';
import './breed-image.css';
function BreedImage () {
const [breed, setBreed] = useState('');
const [url, setUrl] = useState('');
useEffect(() => {
fetchImage();
}, [breed]);
const fetchImage = async () => {
const res = await fetch(`https://dog.ceo/api/breed/${breed}/images/random`)
const data = await res.json();
setUrl(data.message);
};
return (
<>
<DogPicker onChange={(breed) => setBreed(breed)} />
<div className="image-container">
<img className="image-card" src={url} alt="doggopicture" />
</div>
</>
);
}
export default BreedImage;
where you'd pass setBreed to some other component. Or, you could pass breed down to this component as a prop, and again use useEffect to watch for changes.
Related
I'm developing a pokedex using pokeAPI through react, but I'm developing a feature where I can favorite pokemons and with that through a context, I can store the names of these pokemons in a global array. I've already managed to test and verify that the pokemon names are going to this "database" array inside the pokeDatabase const in my context, but my goal now is to pass this array to localstorage so that the browser recognizes these favorite pokemons instead of disappearing every time I refresh the page, my solution was to try to create a useEffect inside the context so that every time I refresh my application, this information is saved in localStorage, but without success. What better way to achieve this?
context:
import { createContext } from "react";
const CatchContext = createContext({
pokemons: null,
});
export default CatchContext;
provider
import React, { useEffect } from "react";
import CatchContext from "./Context";
const pokeDatabase = {
database: [],
};
const CatchProvider = ({ children }) => {
useEffect(() => {
const dataStorage = async () => {
await localStorage.setItem('pokemons', JSON.stringify(pokeDatabase.database));
}
dataStorage();
}, [])
return (
<CatchContext.Provider value={{ pokemons: pokeDatabase }}>
{children}
</CatchContext.Provider>
);
}
export default CatchProvider;
pageAddPokemon
import * as C from './styles';
import { useContext, useEffect, useState } from 'react';
import { useApi } from '../../hooks/useApi';
import { useNavigate, useParams } from 'react-router-dom';
import PokeInfo from '../../components/PokeInfo';
import AddCircleOutlineIcon from '#mui/icons-material/AddCircleOutline';
import DoNotDisturbOnIcon from '#mui/icons-material/DoNotDisturbOn';
import CatchContext from '../../context/Context';
const SinglePokemon = () => {
const api = useApi();
const { pokemons } = useContext(CatchContext);
const { name } = useParams();
const navigate = useNavigate();
const handleHompage = () => {
navigate('/');
}
const [loading, setLoading] = useState(false);
const [imgDatabase, setImgDatabase] = useState('');
const [infoPokemon, setInfoPokemon] = useState([]);
const [pokemonTypes, setPokemonTypes] = useState([]);
const [isCatch, setIsCatch] = useState(false);
useEffect(() => {
const singlePokemon = async () => {
const pokemon = await api.getPokemon(name);
setLoading(true);
setImgDatabase(pokemon.sprites);
setInfoPokemon(pokemon);
setPokemonTypes(pokemon.types);
setLoading(false);
console.log(pokemons.database);
}
singlePokemon();
verifyPokemonInDatabase();
}, []);
const verifyPokemonInDatabase = () => {
if (pokemons.database[infoPokemon.name]) {
return setIsCatch(true);
} else {
return setIsCatch(false);
}
}
const handleCatchAdd = async () => {
if (isCatch === false) {
if (!pokemons.database[infoPokemon.name]);
pokemons.database.push(infoPokemon.name);
setIsCatch(true);
}
}
const handleCatchRemove = async () => {
if (isCatch === true) {
if (!pokemons.database[infoPokemon.name]);
pokemons.database.splice(pokemons.database.indexOf(toString(infoPokemon.name)), 1);
setIsCatch(false);
}
}
return (
<C.Container>
<PokeInfo
name={infoPokemon.name}
/>
<C.Card>
<C.Info>
<C.Imgs>
<img src={imgDatabase.front_default} alt="" />
<img src={imgDatabase.back_default} alt="" />
</C.Imgs>
<h2 id='types'>Tipos</h2>
{pokemonTypes.map(type => {
return (
<C.Types>
<h2>{type.type.name}</h2>
</C.Types>
)
})}
{isCatch ? (
<DoNotDisturbOnIcon id='iconCatched' onClick={handleCatchRemove}/>
): <AddCircleOutlineIcon id='icon' onClick={handleCatchAdd}/>}
</C.Info>
</C.Card>
<C.Return>
<button onClick={handleHompage}>Retornar a Pokédex</button>
</C.Return>
</C.Container>
)
}
export default SinglePokemon;
I am using useEffect and useState hooks to fetch data and destructure it. But I'm getting this error every time.
Here is the code.
import React, { useState, useEffect } from 'react';
import { FaAngleDoubleRight } from 'react-icons/fa';
import Jobs from './Jobs';
// ATTENTION!!!!!!!!!!
// I SWITCHED TO PERMANENT DOMAIN
const url = 'https://course-api.com/react-tabs-project';
function App() {
const [loading, setLoading] = useState(true);
const [jobs, setJobs] = useState([]);
const [value, setValue] = useState(0);
const fetchJobs = async () => {
const response = await fetch(url);
const newJobs = await response.json();
setJobs(newJobs);
setLoading(false);
// console.log(newJobs);
};
useEffect(() => {
fetchJobs();
}, []);
const{company, dates, duties, title}=jobs[value];
console.log(jobs[value]);
// const { company, dates, duties, title } = jobs[value];
return (
<section className='section '>
<div className='title'>
<h2>experience</h2>
<div className='underline'></div>
</div>
{/* <Jobs jobs={jobs} /> */}
</section>
);
}
export default App;
Error image
If I comment out the destructuring, I get the value 6 times. The First 2 times it is undefined.
browser console
You are destructuring properties from the object when still the data is not fetched and the array length is 0
import React, { useState, useEffect } from "react";
import { FaAngleDoubleRight } from "react-icons/fa";
import Jobs from "./Jobs";
// ATTENTION!!!!!!!!!!
// I SWITCHED TO PERMANENT DOMAIN
const url = "https://course-api.com/react-tabs-project";
function App() {
const [loading, setLoading] = useState(true);
const [jobs, setJobs] = useState([]);
const [value, setValue] = useState(0);
const [currentJob, setCurrentJob] = useState();
const fetchJobs = async () => {
const response = await fetch(url);
const newJobs = await response.json();
setJobs(newJobs);
setLoading(false);
if (newJobs.length > 0) setCurrentJob(newJobs[value]);
// console.log(newJobs);
};
useEffect(() => {
fetchJobs();
}, []);
// const{company, dates, duties, title}=jobs[value];
// console.log(jobs[value]);
if (loading) return <h2>Loading...</h2>;
return (
<section className="section ">
<div className="title">
<h2>experience</h2>
<div className="underline"></div>
</div>
{/* <Jobs jobs={jobs} /> */}
</section>
);
}
export default App;
I have added another state variable currentJob which will assume the job item based on value variable when successfully the fetch is completed, although I would suggest to use the jobs array directly based on your component requirements.
I don't understand why the second line, which reads data from the props, is not displayed as instantly as the first, i would like them to be displayed instantly
I update the state when a button is clicked, which calls api, data is coming in, the state is updating, but the second line requires an additional press to display
How to display both lines at once after a call? What's my mistake?
I'm using react hooks, and i know that required to use useEffect for re-render component, i know, that how do work asynchronous call,but i'm a little confused, how can i solve my problem, maybe i need to use 'useDeep effect' so that watching my object properties, or i don't understand at all how to use 'useEffect' in my situation, or even my api call incorrectly?
I have tried many different solution methods, for instance using Promise.all, waiting for a response and only then update the state
index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./test";
ReactDOM.render(<App />, document.getElementById("root"));
app.js
import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
const useDataApi = (initialState) => {
const [state, setState] = useState(initialState);
const stateCopy = [...state];
const setDate = (number, value) => {
setState(() => {
stateCopy[number].date = value;
return stateCopy;
});
};
const setInfo = async () => {
stateCopy.map((item, index) =>
getFetch(item.steamId).then((res) => setDate(index, res.Date))
);
};
const getFetch = async (id) => {
if (id === "") return;
const requestID = await fetch(`https://api.covid19api.com/summary`);
const responseJSON = await requestID.json();
console.log(responseJSON);
const result = await responseJSON;
return result;
};
return { state, setState, setInfo };
};
const Children = ({ data }) => {
return (
<>
<ul>
{data.map((item) => (
<li key={item.id}>
{item.date ? item.date : "Not data"}
<br></br>
</li>
))}
</ul>
</>
);
};
const InfoUsers = ({ number, steamid, change }) => {
return (
<>
<input
value={steamid}
numb={number}
onChange={(e) => change(number, e.target.value)}
/>
</>
);
};
function App() {
const usersProfiles = [
{ date: "", id: 1 },
{ date: "", id: 2 }
];
const profiles = useDataApi(usersProfiles);
return (
<div>
<InfoUsers number={0} change={profiles.setID} />
<InfoUsers number={1} change={profiles.setID} />
<button onClick={() => profiles.setInfo()}>Get</button>
<Children data={profiles.state} loading={profiles} />
</div>
);
}
export default App;
To get the data, just click GET
In this example, completely removed useEffect, maybe i don’t understand how to use it correctly.
P.s: Sorry for bad english
You don't need stateCopy, as you have it in the callback of the setState:
const setInfo = async () => {
// we want to update the component only once
const results = await Promise.all(
state.map(item => getFetch(item.steamId))
);
// 's' is the current state
setState(s =>
results.map((res, index) => ({ ...s[index], date: res.Date })
);
};
import React, { useState, useEffect } from "react";
import { useParams } from "react-router-dom";
import { useGlobalContext } from "../context";
const SingleTvShow = () => {
const { id } = useParams();
const [details, setDetails] = useState({});
const { imgUrl } = useGlobalContext();
const getDetails = async (showId) => {
const resp = await fetch(
`https://api.themoviedb.org/3/tv/${showId}?api_key=API_KEY&language=en-US`
);
const data = await resp.json();
setDetails(data);
};
useEffect(() => {
getDetails(id);
}, [id]);
return (
<div>
{console.log(details)}
<img src={imgUrl + details.backdrop_path} alt="show" />
</div>
);
};
export default SingleTvShow;
https://drive.google.com/file/d/1FhYcJSqZiko0lJBoQdB2Gx5KyMWGR3dj/view?usp=sharing
I just started learning react, please help
Because the initial value of state details is empty {}. details only update when you call api success. Before that, details kept the value {}
You can check like this:
{details.backdrop_path && <img src={imgUrl + details.backdrop_path} alt="show" />}
As #Viet said - the initial value is an empty object {} that is being populated when you have fetched the data.
If you want to show the data to your UI only when the fetching process has been completed then i would suggest changing your return to this:
return (
<div>
{console.log(details)}
{details && <img src={imgUrl + details.backdrop_path} alt="show" /> }
</div>
);
This tells your function to only show the the img element if your state is not an empty object.
I have some data from API that I want to show in another component that is a stateless function.
This is the state - const [user, setUser] = useState([]);
And this is the data I want to output in other components:
const getData = async () => {
const response = await fetch(`https://api.github.com/users/${search}`);
const data = await response.json();
setUser(data);
};
Things I tried for my other component is:
const ProfileImg = props => <img src={props.avatar_url} alt="avatar" />; // or props.user.avatar_url
I tried deconstructing as well but I cannot get the data.
This is the whole form component as what i have now that im trying to pass to other
smaller components.
import React, { useState } from 'react';
import styled from 'styled-components';
const Form = (props) => {
const [search, setSearch] = useState('');
// const [formVal, setForm] = useState('');
const [user, setUser] = useState([]);
const updateSearch = e => {
setSearch(e.target.value);
}
const getSearch = e => {
e.preventDefault();
getData();
// setForm(search);
setSearch('');
}
const getData = async () => {
const response = await fetch(`https://api.github.com/users/${search}`);
const data = await response.json();
setUser(data);
// console.log(data);
}
return (
<React.Fragment>
<StyledForm onSubmit={getSearch}>
<input type="text" value={search} onChange={updateSearch} placeholder="Search for a user" />
</StyledForm>
<div>
<h2>{user.followers}</h2>
</div>
</React.Fragment>
);
}
Not entirely sure if this is what you want but please see below. You seemed to be close with the props on the ProfileImage, but needed a slight change as per below which renders the correct avatar:
import React, {useState, useEffect} from "react";
import ReactDOM from "react-dom";
import "./styles.css";
const ProfileImg = props => <img src={props.user.avatar_url} alt="avatar" />;
function App() {
const [user, setUser] = useState([]);
useEffect(() => {
const getData = async () => {
const response = await fetch(`https://api.github.com/users/h3h394`);
const data = await response.json();
console.log(data);
setUser(data);
};
getData();
});
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<ProfileImg user={user}/>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);