Adding react props to functional components - javascript

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

Related

TypeError: Cannot destructure property 'company' of 'jobs[value]' as it is undefined

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.

Displaying an image from an API In React

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.

React.js: how to create search filter?

I am trying to make work search input. I'm filtering through fetched data in useEffect in Hooks/useCountries component, listening to input in App.js and passing props for handleChange in Searchbar component. Something is missing, I can't figure out what. Here is Hooks/useCountries component
import React, { useState, useEffect } from "react";
export default function useCountries(search) {
const [data, setData] = useState([]);
const [error, setError] = useState(null);
const fetchData = () => {
fetch("https://restcountries.eu/rest/v2/all")
.then((res) => res.json())
.then((result) => setData(result))
.catch((err) => console.log("error"));
};
useEffect(() => {
const searchResult =
data &&
data
.filter((item) => item.name.toLowerCase().includes(search))
.map((element) => <div>{element.name}</div>);
}, []);
useEffect(() => {
fetchData();
}, []);
return [data, error];
}
App.js
import React, { useState } from "react";
import SearchBar from "./components/SearchBar";
import useCountries from "./Hooks/useCountries";
import MainTable from "./components/MainTable";
import "./App.scss";
export default function App() {
const [search, setSearch] = useState("");
const [data, error] = useCountries(search);
const handleChange = (e) => {
setSearch(e.target.value);
};
return (
<div className="App">
<SearchBar handleChange={handleChange} search={search} />
<MainTable countries={data} />
</div>
);
}
SearchBar component
import React, { useState } from "react";
import "./SearchBar.scss";
export default function Searchbar({ handleChange, search }) {
return (
<div className="SearchBar">
<input
className="input"
type="text"
placeholder="search country ..."
value={search}
onChange={handleChange}
/>
</div>
);
}
The useEffect method you have which performs the filtering needs to be fired each time the search term changes - currently you are only using it once when the hook is created for the first time:
useEffect(() => {
const searchResult =
data &&
data
.filter((item) => item.name.toLowerCase().includes(search))
.map((element) => <div>{element.name}</div>);
}, [search]);
Note how the search variable is now part of the useEffect dependency array.

I am unable to fetch different values from API except for "chicken"

As the query will fetch the value that is provided in useState. But I want the search bar to search for recipes provided by me. Can anybody help me on how I can do that.
import React, { useEffect, useState } from 'react';
import Recipe from './Recipe';
import './App.css';
const App = ()=>{
const APP_ID= '2*****'
const APP_KEY= 'f******************'
const [recipes, setRecipes] = useState([]);
const [search, setSearch] = useState("");
const [query, setQuery] = useState('chicken');
useEffect(() =>{
const getRecipes = async()=>{
const response = await fetch(`https://api.edamam.com/search?q=${query}&app_id=${APP_ID}&app_key=${APP_KEY}`);
const data = await response.json();
setRecipes(data.hits)
};
getRecipes();
},[query]);
const updateSearch = e=>{
setSearch(e.target.value);
}
const getSearch = e =>{
setQuery(search);
setSearch('');
}
return(
<div className="App">
<form onSubmit={getSearch} className="search-form">
<input className="search-bar" type="text" value={search} onChange={updateSearch} />
<button className="search-button" type="submit">Search</button>
</form>
{recipes.map(recipe =>(
<Recipe
key={recipe.recipe.label}
title={recipe.recipe.label}
calories={recipe.recipe.calories}
image={recipe.recipe.image} />
))}
</div>
)
}
export default App;
don't create multiple states for the same thing.
pass search string to the fetch API
import React, { useState, useEffect } from "react";
import "./styles.css";
const App = () => {
const APP_ID = "2***********";
const APP_KEY = "f*********";
const [recipes, setRecipes] = useState([]);
const [search, setSearch] = useState("");
useEffect(() => {
try {
const getRecipes = async () => {
const response = await fetch(
`https://api.edamam.com/search?q=${search}&app_id=${APP_ID}&app_key=${APP_KEY}`
);
const data = await response.json();
setRecipes(data.hits);
};
getRecipes();
} catch (error) {
// handle error here
console.error(error);
}
}, [search]);
const updateSearch = (e) => {
setSearch(e.target.value);
};
const getSearch = (e) => {
setSearch("");
};
return (
<div className="App">
<form onSubmit={getSearch} className="search-form">
<input
className="search-bar"
type="text"
value={search}
onChange={updateSearch}
/>
<button className="search-button" type="submit">
Search
</button>
</form>
{recipes.map((recipe) => (
<Recipe
key={recipe.recipe.label}
title={recipe.recipe.label}
calories={recipe.recipe.calories}
image={recipe.recipe.image}
/>
))}
</div>
);
};
export default App;
edit:
If initially, you want to have chicken results from API, change the response variable to this:
const response = await fetch(
`https://api.edamam.com/search?q=${search || "chicken"}&app_id=${APP_ID}&app_key=${APP_KEY}`
);

React.js: why search filter doesn't work?

I am trying to make work search input. I'm filtering through fetched data in useEffect in Hooks/useCountries component, listening to input in App.js and passing props for handleChange in Searchbar component. Something is missing, I can't figure out what. Here is the link of codesandbox and Hooks/useCountries component
import React, { useState, useEffect } from "react";
export default function useCountries(search) {
const [data, setData] = useState([]);
const [error, setError] = useState(null);
const fetchData = () => {
fetch("https://restcountries.eu/rest/v2/all")
.then((res) => res.json())
.then((result) => setData(result))
.catch((err) => console.log("error"));
};
useEffect(() => {
const searchResult =
data &&
data
.filter((item) => item.name.toLowerCase().includes(search))
.map((element) => <div>{element.name}</div>);
}, []);
useEffect(() => {
fetchData();
}, []);
return [data, error];
}
App.js
import React, { useState } from "react";
import SearchBar from "./components/SearchBar";
import useCountries from "./Hooks/useCountries";
import MainTable from "./components/MainTable";
import "./App.scss";
export default function App() {
const [search, setSearch] = useState("");
const [data, error] = useCountries(search);
const handleChange = (e) => {
setSearch(e.target.value);
};
return (
<div className="App">
<SearchBar handleChange={handleChange} search={search} />
<MainTable countries={data} />
</div>
);
}
SearchBar component
import React, { useState } from "react";
import "./SearchBar.scss";
export default function Searchbar({ handleChange, search }) {
return (
<div className="SearchBar">
<input
className="input"
type="text"
placeholder="search country ..."
value={search}
onChange={handleChange}
/>
</div>
);
}
So in your useCountries hook, you need to update the useEffect to trigger whenever search is changed. Otherwise, it runs when the hook is first loaded, but then never again. I'm also not exactly sure what your logic is attempting to accomplish in your current useEffect. I've posted a possible update to it that also changes your search to regex to account for the possibility that the user may not be typing in lower case. Let me know if this doesn't work for your use case and I can adapt it.
import React, { useState, useEffect } from "react";
export default function useCountries(search) {
const [data, setData] = useState([]);
const [error, setError] = useState(null);
const [searchResults, setSearchResults] = useState(null);
const fetchData = () => {
fetch("https://restcountries.eu/rest/v2/all")
.then((res) => res.json())
.then((result) => setData(result))
.catch((err) => console.log("error"));
};
useEffect(() => {
if (search) {
const searchCriteria = new RegExp(search, "i");
setSearchResults(
data
.filter((item) => searchCriteria.test(item.name))
.map((element) => <div>{element.name}</div>)
);
} else {
setSearchResults(null);
}
}, [search]);
useEffect(() => {
fetchData();
}, []);
return [data, error, searchResults];
}
And in App.js add:
const [data, error, searchResults] = useCountries(search);
Here is the fork off of your sandbox where this works:
CodeSandbox

Categories