Unsplash API with React Part 3
Search Feature
So glad you’ve made it this far. We now have fetched data and rendered the most recent thirty images from Unsplash’s home page editorial feed as an image gallery on page load and we can also view a larger version of each image via a modal on click. We now want to add a search feature.
In our Components
folder let’s create a SearchBar
component as a functional component passing in props
. Let’s also destructure fetchInitialImages
as well as two other functions we still have to create — handleChange
and handleSubmit
. We’ll also return some Bootstrap code to set up a ‘navbar’ as a heading which is where we will have a brand name and a search form. Grab the snippet of code that has the comment <!-- As a heading -->
above it. We’ll wrap the content of the navbar in a div.container
and add a search form that is aligned to the right. We can rename the content of the span tag so that our app has a title. I will simply title this example Brand Name
. We’ll also add an onClick
to the title that fires the fetchInitialImages
function so that it acts as a ‘home’ button. Even though this app is only one page, when we search for different categories, we should have the option for the user to go back to the initial Curated Collection category. To that end, I also styled the mouse cursor to be a pointer. Since the title is a span
tag with just text, the mouse cursor will become a line cursor when it hovers over it. So by styling it to be a pointer it indicates to the user that it is clickable. Our SearchBar
component should look something like this:
import React from 'react'const SearchBar = (props) => {
const { fetchInitialImages, handleChange, handleSubmit } = props
return(
<nav className="navbar navbar-expand-lg navbar-light bg-light">
<div className="container">
<span className="navbar-brand" onClick={fetchInitialImages} style={{cursor: 'pointer'}}>Brand Name</span>
<form className="form-inline my-2 my-lg-0 ml-auto" onSubmit={handleSubmit}>
<input className="form-control mr-sm-2" type="search" aria-label="Search" onChange={handleChange} />
<button className="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
</form>
</div>
</nav>
)
}export default SearchBar
Notice there are onSubmit
and onChange
event listeners on the form
and input
tags respectively. Let’s set those up now. Going back to our App
component we’ll first add a currentQuery
property to the state in the constructor
function. Then we’ll set up the handleChange
function to set the state of the currentQuery
to e.target.value
which will be the value of the search input field.
handleChange = (e) => {
this.setState({currentQuery: e.target.value})
}
For handleSubmit
, after firing the e.preventDefault()
function we’ll set the searchedQuery
to the currentQuery
. We’ll also update the gallery
array by fetching another 30 data objects of the specified search term and removing the previous items in the array since this is a new gallery we are rendering:
handleSubmit = (e) => {
e.preventDefault()
this.setState((prevState) => {
return {searchedQuery: prevState.currentQuery}
})
axios.get(`${this.ROOT}search/photos${this.KEY}&query=${this.state.currentQuery}${this.PERPAGE}`)
.then(res => {
let results = res.data.results
console.log('results = ', results)
this.setState({gallery: [...results]})
})
.catch(error => console.log(error))
}
And of course we need to import our SearchBar
into App
and pass those functions to the SearchBar
component:
import React, { Component } from 'react'
import axios from 'axios'
import SearchBar from './Components/SearchBar'
import Gallery from './Components/Gallery'
.
.
.
render() {
return (
<div className="App">
<SearchBar fetchInitialImages={this.fetchInitialImages} handleChange={this.handleChange} handleSubmit={this.handleSubmit} />
<Gallery gallery={this.state.gallery} launchModal={this.launchModal} selectedImage={this.state.selectedImage} />
</div>
);
}
}
export default App
Boom! Now you should have a functioning search form 😊 The final feature will be to add a ‘Load More’ button so a user can view another thirty images of the same category. See you there!