Reputation: 87
I am new to ReactJS and I am trying to create a search feature with react by fetching data from multiple API. Below is the Search.js file. I tried so many times to make it functions and make the results appear live while typing. I however keep on getting this error message TypeError: values.map is not a function. Where am I going wrong and how do I fix it?
function Search() {
const [input, setInput] = useState("");
const [results, setResults] = useState([]);
const urls = [
'https://jsonplaceholder.typicode.com/posts/1/comments',
'https://jsonplaceholder.typicode.com/comments?postId=1'
]
Promise.all(urls.map(url => fetch(url)
.then((values) => Promise.all(values.map(value => value.json())))
.then((response) => response.json())
.then((data) => setResults(data))
.catch(error => console.log('There was a problem!', error))
), [])
const handleChange = (e) => {
e.preventDefault();
setInput(e.target.value);
}
if (input.length > 0) {
results.filter((i) => {
return i.name.toLowerCase().match(input);
})
}
return ( <
div className = "search"
htmlFor = "search-input" >
<
input type = "text"
name = "query"
value = {
input
}
id = "search"
placeholder = "Search"
onChange = {
handleChange
}
/> {
results.map((result, index) => {
return ( <
div className = "results"
key = {
index
} >
<
h2 > {
result.name
} < /h2> <
p > {
result.body
} < /p> {
result
} <
/div>
)
})
} </div>
)
}
.search {
position: relative;
left: 12.78%;
right: 26.67%;
top: 3%;
bottom: 92.97%;
}
.search input {
/* position: absolute; */
width: 40%;
height: 43px;
right: 384px;
margin-top: 50px;
top: 1.56%;
bottom: 92.97%;
background: rgba(0, 31, 51, 0.02);
border: 1px solid black;
border-radius: 50px;
float: left;
outline: none;
font-family: 'Montserrat', sans-serif;
font-style: normal;
font-weight: normal;
font-size: 16px;
line-height: 20px;
/* identical to box height */
display: flex;
align-items: center;
/* Dark */
color: #001F33;
}
/* Search Icon */
input#search {
background-repeat: no-repeat;
text-indent: 50px;
background-size: 18px;
background-position: 30px 15px;
}
input#search:focus {
background-image: none;
text-indent: 0px
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Upvotes: 1
Views: 1656
Reputation: 203051
fetch(url)
is just the one single response, so there's nothing to map.input.length > 0
filtering before the return does nothing since the returned filtered array isn't saved, and it also incorrectly searches for sub-strings.result
object in the render function, objects are invalid JSX.then((values) => Promise.all(values.map((value) => value.json())))
step and just move on to accessing the JSON data.useEffect
hook so it's run only once.result
object I'll assume you probably wanted to render the email
property.Code:
function Search() {
const [input, setInput] = useState("");
const [results, setResults] = useState([]);
useEffect(() => {
const urls = [
"https://jsonplaceholder.typicode.com/posts/1/comments",
"https://jsonplaceholder.typicode.com/comments?postId=1"
];
Promise.all(
urls.map((url) =>
fetch(url)
.then((response) => response.json())
.then((data) => setResults(data))
.catch((error) => console.log("There was a problem!", error))
),
[]
);
}, []);
const handleChange = (e) => {
e.preventDefault();
setInput(e.target.value.toLowerCase());
};
return (
<div className="search" htmlFor="search-input">
<input
type="text"
name="query"
value={input}
id="search"
placeholder="Search"
onChange={handleChange}
/>
{results
.filter((i) => i.name.toLowerCase().includes(input))
.map((result, index) => {
return (
<div className="results" key={index}>
<h2>{result.name}</h2>
<p>{result.body}</p>
{result.email}
</div>
);
})}
</div>
);
}
Upvotes: 2